zucommunications/health-check-bundle
A Laravel/PHP health-check bundle that exposes configurable endpoints for monitoring application status and dependencies. Add readiness and liveness checks for databases, cache, queues, and custom services, making it easy to integrate with uptime monitors and load balancers.
Start by confirming the fit: this is a Symfony bundle (symfony/framework-bundle), not a Laravel package. Laravel apps can consume it, but only after pulling in the FrameworkBundle/DI layer — for most Laravel projects you'll get more signal from a native health-check implementation than from adopting a bundle that isn't built around Laravel's service container.
If you are in a Symfony app (or a Laravel app already running Symfony's FrameworkBundle):
composer require zucommunications/health-check-bundle:^0.3config/bundles.phpconfig/routes.yaml)/health (or whatever path the bundle exposes) and verify a 200 for a healthy app and a 5xx when a dependency is downLook first at:
Resources/config/ (or config/) directory for the default service definitions and the default check setCheckInterface with a check(): Result-style method)First real use case: wire the endpoint into a load balancer / uptime monitor (or a Kubernetes liveness/readiness probe) and keep the check list to things that matter — database connectivity, cache, and maybe queue. Don't add every dependency on day one.
Default endpoint + probe pattern. Mount the health route and point your infrastructure at it. Keep the public endpoint returning a coarse status (healthy/unhealthy); log the per-check detail server-side rather than exposing it in the body.
Custom checks as tagged services. The idiomatic Symfony pattern is to implement the check interface and tag the service (e.g. health_check.check — verify the exact tag name in the bundle's service config). Auto-configuration via _instanceof in services.yaml is usually cleaner than tagging each service by hand.
services:
_instanceof:
Vendor\HealthCheck\CheckInterface:
tags: ['health_check.check']
Separate liveness from readiness. Liveness should be cheap (app booted), readiness should exercise dependencies. If the bundle exposes only one endpoint, register two routes pointing to different check sets, or keep the dependency checks in a second "deep" endpoint that your orchestrator calls less frequently.
Fail fast inside checks. Every check should have a short internal timeout (DB ping, Redis PING, HTTP HEAD). A health endpoint that blocks for 30s because a downstream is hanging will cascade into your load balancer marking the whole fleet unhealthy.
CI integration. Call the endpoint in your post-deploy smoke test and assert 200; assert 503 in a negative test where you deliberately point a check at a dead dependency.
Custom check skeleton.
final class RedisCheck implements CheckInterface
{
public function __construct(private \Redis $redis) {}
public function check(): CheckResult
{
try {
$this->redis->ping();
return CheckResult::healthy('redis');
} catch (\Throwable $e) {
return CheckResult::unhealthy('redis', $e->getMessage());
}
}
}
Response handling. Don't let the endpoint throw on a failed check — catch inside the check and return an unhealthy result, otherwise you get a generic 500 with no per-check detail in the logs.
This is a Symfony bundle, not a Laravel package. That's the biggest gotcha. symfony/framework-bundle is not part of a default Laravel install, so the bundle's routing, DI tagging, and config tree won't wire up without adding the FrameworkBundle to a Laravel app — which is a lot of machinery for a health endpoint. If your team is Laravel-first, treat this as reference material for what checks to implement, and build the endpoint with a Laravel controller + service provider instead.
Pre-1.0 semver. You're on 0.3.x. Anything can change in a minor. Pin to ^0.3 and read the diff on upgrade; don't assume the route path, config keys, or check interface are stable.
Symfony 7 compatibility is new in 0.3.0. If you're on Symfony 7 (or Laravel 11+ with Symfony 7 components), you need >=0.3.0 — earlier versions will fail on constraint resolution or runtime API mismatches. Conversely, if you're pinned to Symfony 6.x, 0.2.x may still be the safer choice; check the bundle's composer.json constraints rather than assuming 0.3 is backward-compatible with 6.x.
Watch the transitive footprint. Symfony 7 support often means relaxed constraints across the dependency graph. Run composer why-not / composer outdated after installing in a real app to confirm it hasn't pulled your Symfony component versions forward unexpectedly.
Configuration quirks. Bundle config trees often apply defaults you didn't ask for (e.g. all discovered checks enabled by default). Explicitly enable the checks you want rather than relying on discovery — otherwise adding a new tagged service silently changes your health endpoint's behaviour.
Don't leak internals. Exception messages, DSNs, and stack traces must not appear in the HTTP response. Keep the response body to status + check names; put the detail behind a log channel or a separately authenticated admin route.
Caching the result. If the endpoint is polled every second by a load balancer, a tiny cache (a few seconds) on the expensive checks prevents your health endpoint from becoming its own load source on the database.
Extension points to note. The check interface + service tag is the intended extension seam; the config tree is the intended behaviour seam. Avoid subclassing the bundle's internals — those are the most likely to move between 0.x releases.
How can I help you explore Laravel packages today?