rasuvaeff/yii3-health-check

Health check endpoints for Yii3 applications

Maintainers

Package info

github.com/rasuvaeff/yii3-health-check

pkg:composer/rasuvaeff/yii3-health-check

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.1 2026-06-02 16:59 UTC

This package is auto-updated.

Last update: 2026-06-02 16:59:59 UTC


README

Stable Version Total Downloads Build Static Analysis Coverage Psalm Level License

Health check endpoints for Yii3: /live, /ready, /health. PSR-15 request handlers with composite checks, elapsed time tracking and Kubernetes probe support.

Using an AI coding assistant? llms.txt has a compact API reference ready to paste into context.

Requirements

  • PHP 8.3+
  • psr/clock ^1.0
  • psr/http-factory ^1.0
  • psr/http-message ^2.0
  • psr/http-server-handler ^1.0

Installation

composer require rasuvaeff/yii3-health-check

Usage

1. Register routes

// config/routes.php
use Rasuvaeff\Yii3HealthCheck\HealthEndpoint;
use Rasuvaeff\Yii3HealthCheck\LivenessEndpoint;
use Rasuvaeff\Yii3HealthCheck\ReadinessEndpoint;
use Yiisoft\Router\Route;

return [
    Route::get('/live')->action(LivenessEndpoint::class)->name('health.live'),
    Route::get('/ready')->action(ReadinessEndpoint::class)->name('health.ready'),
    Route::get('/health')->action(HealthEndpoint::class)->name('health.full'),
];

2. Register your checks in DI

The package ships config/di.php and config/params.php via config-plugin. Extend HealthChecker with your own checks:

// config/di.php
use App\Infrastructure\Health\DatabaseHealthCheck;
use App\Infrastructure\Health\RedisHealthCheck;
use Rasuvaeff\Yii3HealthCheck\HealthChecker;
use Yiisoft\Definitions\Reference;

return [
    HealthChecker::class => [
        '__construct()' => [
            'checks' => [
                Reference::to(DatabaseHealthCheck::class),
                Reference::to(RedisHealthCheck::class),
            ],
            'warnThresholdMs' => $params['rasuvaeff/yii3-health-check']['warnThresholdMs'],
        ],
    ],
];

3. Implement your checks

// src/Infrastructure/Health/DatabaseHealthCheck.php
use Rasuvaeff\Yii3HealthCheck\HealthCheck;
use Rasuvaeff\Yii3HealthCheck\HealthResult;
use Yiisoft\Db\Connection\ConnectionInterface;

final readonly class DatabaseHealthCheck implements HealthCheck
{
    public function __construct(private ConnectionInterface $db) {}

    public function name(): string
    {
        return 'database';
    }

    public function check(): HealthResult
    {
        try {
            $this->db->createCommand('SELECT 1')->queryScalar();
            return HealthResult::pass(name: 'database');
        } catch (\Throwable $e) {
            return HealthResult::fail(name: 'database', message: $e->getMessage());
        }
    }
}

For inline checks without a dedicated class use CallbackHealthCheck:

use Rasuvaeff\Yii3HealthCheck\CallbackHealthCheck;
use Rasuvaeff\Yii3HealthCheck\HealthResult;

new CallbackHealthCheck(
    name: 'disk',
    check: static function (): HealthResult {
        $free = disk_free_space('/');
        if ($free === false) {
            return HealthResult::fail(name: 'disk', message: 'Cannot read disk stats');
        }
        if ($free < 100 * 1024 * 1024) {
            return HealthResult::warn(name: 'disk', message: 'Less than 100MB free',
                data: ['freeBytes' => $free]);
        }
        return HealthResult::pass(name: 'disk');
    },
)

Liveness vs Readiness

Endpoint Handler Checks k8s probe On failure
/live LivenessEndpoint None (always pass) livenessProbe Container restart
/ready ReadinessEndpoint All registered checks readinessProbe Removed from load balancer
/health HealthEndpoint All registered checks Monitoring/dashboard

Rule: never put external service checks (DB, Redis) in liveness — a slow DB would restart your container. Put them only in readiness.

API reference

HealthResult

HealthResult::pass(name: 'db')
HealthResult::pass(name: 'db', message: 'Connected')
HealthResult::warn(name: 'db', message: 'Slow', data: ['latencyMs' => 950])
HealthResult::fail(name: 'db', message: 'Connection refused')

$result->name       // string
$result->status     // HealthStatus
$result->message    // string
$result->data       // array<string, mixed>
$result->elapsedMs  // float (set by HealthChecker)

$result->withData(['rows' => 42])   // returns new instance
$result->withElapsedMs(12.5)        // returns new instance
$result->toArray()                  // array, omits elapsedMs:0 and data:[], always includes message

HealthStatus

HealthStatus::Pass  // 'pass' → HTTP 200
HealthStatus::Warn  // 'warn' → HTTP 200
HealthStatus::Fail  // 'fail' → HTTP 503

HealthChecker

$checker = new HealthChecker(
    checks: [$dbCheck, $redisCheck],
    clock: $psrClock,          // optional PSR-20, default microtime()
    warnThresholdMs: 500.0,    // default 1000.0
);

$checker->add($check);                        // add a check at runtime
$checker->has('database');                    // bool
$results = $checker->run();                   // array<string, HealthResult>
$results = $checker->runByName('database');   // array<string, HealthResult>

HealthChecker::aggregateStatus($results);     // HealthStatus

Aggregation rules:

Condition Result
Any fail fail
Any warn, no fail warn
All pass pass

HealthCheck interface

interface HealthCheck
{
    public function name(): string;   // /^[a-z][a-z0-9_.-]*$/
    public function check(): HealthResult;
}

Exception thrown from check() is caught and converted to HealthResult::fail.

LivenessEndpoint

new LivenessEndpoint(
    responseFactory: $factory,
    statusMessage: 'alive',    // optional, default 'alive'
)

Always returns HTTP 200. Never depends on external services.

{"status":"pass","message":"alive"}

ReadinessEndpoint / HealthEndpoint

new ReadinessEndpoint(checker: $checker, responseFactory: $factory)
new HealthEndpoint(checker: $checker, responseFactory: $factory)

Both run all registered checks and return the same JSON format.

{
    "status": "warn",
    "checks": {
        "database": {"name":"database","status":"pass","message":"","elapsedMs":2.1},
        "redis":    {"name":"redis","status":"warn","message":"Check took 1243.0ms (threshold: 1000.0ms)","elapsedMs":1243.0}
    }
}

Warn threshold

warnThresholdMs (default: 1000ms) automatically upgrades passwarn when a check takes too long. Existing warn and fail statuses are never downgraded:

// warnThresholdMs: 500
// database check took 750ms → upgraded to warn automatically
{"name":"database","status":"warn","message":"Check took 750.0ms (threshold: 500.0ms)","elapsedMs":750.0}

Configure via params.php:

'rasuvaeff/yii3-health-check' => [
    'warnThresholdMs' => 500.0,
    'livenessMessage' => 'alive',
],

Kubernetes probes

livenessProbe:
  httpGet:
    path: /live
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 10
  failureThreshold: 3

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 10
  failureThreshold: 3

Security

  • Check names validated: /^[a-z][a-z0-9_.-]*$/
  • Callbacks are developer-controlled, no user input executed
  • Liveness never exposes internal service state

Examples

See examples/ for runnable scripts and a full Yii3 wiring guide.

Development

make install
make build
make cs:fix
make mutation

License

BSD-3-Clause. See LICENSE.md.