Skip to content

Commit 9beb4cb

Browse files
committed
Add health check endpoint
1 parent 0d41d33 commit 9beb4cb

File tree

2 files changed

+204
-0
lines changed

2 files changed

+204
-0
lines changed

examples/app-api/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ curl -b cookies.txt http://localhost:9501/site/get-cookie
5555
curl http://localhost:9501/site/sleep?seconds=2
5656
```
5757

58+
### Health Check
59+
```bash
60+
# Comprehensive health check (all services)
61+
curl http://localhost:9501/health
62+
63+
# Liveness probe (application running)
64+
curl http://localhost:9501/health/live
65+
66+
# Readiness probe (ready to serve traffic)
67+
curl http://localhost:9501/health/ready
68+
```
69+
5870
### Connection Pools
5971

6072
**Redis Pool:**
@@ -158,6 +170,7 @@ YII_SESSION_TIMEOUT=1440
158170
| Feature | Controller | Description |
159171
|---------|------------|-------------|
160172
| HTTP Server | `SiteController` | Request handling, cookies, coroutine sleep |
173+
| Health Check | `HealthController` | Monitor application and service health status |
161174
| Redis Pool | `RedisController` | Connection pooling, concurrent access, benchmarks |
162175
| DB Pool | `UserController` | Database connection pooling, user queries |
163176
| Session | `SessionController` | Coroutine-safe session storage via Redis |
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
<?php
2+
3+
namespace app\controllers;
4+
5+
use Yii;
6+
use yii\web\Controller;
7+
8+
/**
9+
* Health check controller
10+
* Provides endpoints for monitoring application and service health
11+
*/
12+
class HealthController extends Controller
13+
{
14+
/**
15+
* Health check endpoint
16+
* Returns the health status of the application and its dependencies
17+
*
18+
* @return array Health status information
19+
*/
20+
public function actionIndex()
21+
{
22+
$startTime = microtime(true);
23+
$status = 'healthy';
24+
$checks = [];
25+
26+
// Check PHP version
27+
$checks['php'] = [
28+
'status' => 'ok',
29+
'version' => PHP_VERSION,
30+
];
31+
32+
// Check Swoole
33+
$checks['swoole'] = [
34+
'status' => 'ok',
35+
'version' => swoole_version(),
36+
'coroutine_id' => \Swoole\Coroutine::getCid(),
37+
];
38+
39+
// Check database connection
40+
if (Yii::$app->has('db')) {
41+
try {
42+
$dbStartTime = microtime(true);
43+
$result = Yii::$app->db->createCommand('SELECT 1')->queryScalar();
44+
$dbTime = round((microtime(true) - $dbStartTime) * 1000, 2);
45+
46+
$checks['database'] = [
47+
'status' => $result === 1 ? 'ok' : 'error',
48+
'response_time_ms' => $dbTime,
49+
];
50+
51+
// Check for connection pool stats if available
52+
if (method_exists(Yii::$app->db, 'getPool')) {
53+
$poolStats = Yii::$app->db->getPool()->getStats();
54+
$checks['database']['pool'] = $poolStats;
55+
}
56+
} catch (\Throwable $e) {
57+
$status = 'unhealthy';
58+
$checks['database'] = [
59+
'status' => 'error',
60+
'error' => $e->getMessage(),
61+
];
62+
}
63+
}
64+
65+
// Check Redis connection
66+
if (Yii::$app->has('redis')) {
67+
try {
68+
$redisStartTime = microtime(true);
69+
$result = Yii::$app->redis->executeCommand('PING');
70+
$redisTime = round((microtime(true) - $redisStartTime) * 1000, 2);
71+
72+
$checks['redis'] = [
73+
'status' => $result === 'PONG' ? 'ok' : 'error',
74+
'response_time_ms' => $redisTime,
75+
];
76+
77+
// Check for connection pool stats if available
78+
if (method_exists(Yii::$app->redis, 'getPool')) {
79+
$poolStats = Yii::$app->redis->getPool()->getStats();
80+
$checks['redis']['pool'] = $poolStats;
81+
}
82+
} catch (\Throwable $e) {
83+
$status = 'unhealthy';
84+
$checks['redis'] = [
85+
'status' => 'error',
86+
'error' => $e->getMessage(),
87+
];
88+
}
89+
}
90+
91+
// Check queue if configured
92+
if (Yii::$app->has('queue')) {
93+
try {
94+
$checks['queue'] = [
95+
'status' => 'ok',
96+
'class' => get_class(Yii::$app->queue),
97+
];
98+
} catch (\Throwable $e) {
99+
$checks['queue'] = [
100+
'status' => 'error',
101+
'error' => $e->getMessage(),
102+
];
103+
}
104+
}
105+
106+
// Memory usage
107+
$checks['memory'] = [
108+
'status' => 'ok',
109+
'usage_mb' => round(memory_get_usage(true) / 1024 / 1024, 2),
110+
'peak_mb' => round(memory_get_peak_usage(true) / 1024 / 1024, 2),
111+
];
112+
113+
// Coroutine stats
114+
$coroutineStats = \Swoole\Coroutine::stats();
115+
$checks['coroutines'] = [
116+
'status' => 'ok',
117+
'count' => $coroutineStats['coroutine_num'] ?? 0,
118+
'peak' => $coroutineStats['coroutine_peak_num'] ?? 0,
119+
];
120+
121+
$totalTime = round((microtime(true) - $startTime) * 1000, 2);
122+
123+
// Set appropriate HTTP status code
124+
$httpStatus = $status === 'healthy' ? 200 : 503;
125+
Yii::$app->response->setStatusCode($httpStatus);
126+
127+
return $this->asJson([
128+
'status' => $status,
129+
'timestamp' => time(),
130+
'response_time_ms' => $totalTime,
131+
'checks' => $checks,
132+
]);
133+
}
134+
135+
/**
136+
* Liveness probe endpoint
137+
* Simple endpoint to check if the application is running
138+
*
139+
* @return array Liveness status
140+
*/
141+
public function actionLive()
142+
{
143+
return $this->asJson([
144+
'status' => 'alive',
145+
'timestamp' => time(),
146+
]);
147+
}
148+
149+
/**
150+
* Readiness probe endpoint
151+
* Checks if the application is ready to serve traffic
152+
*
153+
* @return array Readiness status
154+
*/
155+
public function actionReady()
156+
{
157+
$ready = true;
158+
$checks = [];
159+
160+
// Check critical services only
161+
if (Yii::$app->has('db')) {
162+
try {
163+
Yii::$app->db->createCommand('SELECT 1')->queryScalar();
164+
$checks['database'] = 'ready';
165+
} catch (\Throwable $e) {
166+
$ready = false;
167+
$checks['database'] = 'not ready';
168+
}
169+
}
170+
171+
if (Yii::$app->has('redis')) {
172+
try {
173+
Yii::$app->redis->executeCommand('PING');
174+
$checks['redis'] = 'ready';
175+
} catch (\Throwable $e) {
176+
$ready = false;
177+
$checks['redis'] = 'not ready';
178+
}
179+
}
180+
181+
$httpStatus = $ready ? 200 : 503;
182+
Yii::$app->response->setStatusCode($httpStatus);
183+
184+
return $this->asJson([
185+
'status' => $ready ? 'ready' : 'not ready',
186+
'timestamp' => time(),
187+
'checks' => $checks,
188+
]);
189+
}
190+
}
191+

0 commit comments

Comments
 (0)