Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Symfony Health Check Bundle Laravel Package

jpvdw86/symfony-health-check-bundle

A Symfony bundle that adds a health check endpoint to your application, aggregating checks such as database, cache, and disk to report overall status for monitoring tools, load balancers, and uptime probes.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package. There is no extra.laravel.providers, no service provider, and no auto-discovery. composer require jpvdw86/symfony-health-check-bundle will install code into vendor/, but in a stock Laravel app it will do nothing on its own. Treat it as one of two things:

  1. A sidecar/pattern reference — read the checkers and aggregator and port the pattern into Laravel.
  2. A Symfony microservice — stand up a tiny Symfony app that owns /health and probes the same infrastructure your Laravel app uses (DB, Redis, queue, storage).

Minimal first steps (Symfony context, to understand the package):

composer require jpvdw86/symfony-health-check-bundle
// config/bundles.php
return [
    // ...
    Vendor\HealthCheckBundle\HealthCheckBundle::class => ['all' => true],
];
# config/routes.yaml
health_check:
    resource: "@HealthCheckBundle/Resources/config/routes.yaml"

Then look here first, in this order:

  • vendor/jpvdw86/symfony-health-check-bundle/src/ — find the bundle class, the controller, and the checker interface/contract.
  • DependencyInjection/Configuration.php — this is the source of truth for what is configurable. If it isn’t in the config tree, it isn’t a supported option.
  • DependencyInjection/*Extension.php — shows which services are tagged and how checkers are collected.
  • Any health_check.checker (or similarly named) service tag — this is the main extension point.

First use case: a database connectivity check exposed at GET /health returning 200 with a JSON body when the DB answers and 503 when it doesn’t. Wire that up, curl it locally, then wire it into your probe/uptime monitor.

For a Laravel app, the realistic “first use case” is a 30-line port:

// routes/web.php or routes/api.php
Route::get('/health', function () {
    try {
        DB::connection()->getPdo();
        return response()->json(['status' => 'ok']);
    } catch (\Throwable $e) {
        report($e);
        return response()->json(['status' => 'fail'], 503);
    }
});

Then grow it toward the package’s model: multiple named checkers aggregated into one report.

Implementation Patterns

1. Tagged checkers + aggregator (the core pattern to copy)

The package’s useful idea is that each dependency is an isolated checker, registered as a service, tagged, and run by an aggregator. Recreate that in Laravel rather than trying to boot the bundle:

// app/Health/Checker.php
interface Checker
{
    public function name(): string;
    public function check(): CheckResult; // { healthy: bool, message: ?string, meta: array }
}
// app/Providers/HealthServiceProvider.php
public function register(): void
{
    $this->app->tag([
        \App\Health\Checkers\DatabaseChecker::class,
        \App\Health\Checkers\CacheChecker::class,
        \App\Health\Checkers\QueueChecker::class,
        \App\Health\Checkers\StorageChecker::class,
    ], 'health.checker');

    $this->app->singleton(HealthManager::class, fn ($app) =>
        new HealthManager($app->tagged('health.checker'))
    );
}

This gives you the same benefits the bundle gives Symfony devs: add a check by adding a class + tag, no controller edits.

2. Split liveness from readiness

Do not put a DB check behind a Kubernetes liveness probe. A transient DB outage will restart every pod and turn a degraded dependency into a full outage. Mirror the Symfony convention of cheap-vs-deep endpoints:

  • GET /health/live — “is the PHP process alive?” No I/O. Always 200 unless the app is broken.
  • GET /health/ready — DB, Redis, queue backlog, storage writability. Returns 503 when a dependency is down.
  • GET /health/deep — full report, optional auth/token, used by dashboards and humans.

3. Probe-friendly responses and status codes

Load balancers and orchestrators only understand the status code; humans read the body. Return both:

return response()->json([
    'status' => $report->isHealthy() ? 'ok' : 'fail',
    'checks' => $report->toArray(), // name => {status, duration_ms, message}
    'version' => config('app.version'),
], $report->isHealthy() ? 200 : 503);

Keep the body shape stable — your uptime monitor will parse it.

4. Cache the expensive checks

Probes often fire every 5–10 seconds per replica. Hitting the DB and Redis on every probe is self-inflicted load. Cache the aggregated report briefly, keyed by a hash of the enabled checkers:

$report = Cache::remember('health:report', now()->addSeconds(10), fn () =>
    $this->manager->run()
);

Add an ?fresh=1 (auth-protected) escape hatch for on-call debugging.

5. Port the checkers that map to Laravel primitives

Concept Symfony bundle equivalent Laravel implementation
DB PDO/Doctrine check DB::select('select 1') or DB::connection()->getPdo()
Cache cache pool check Cache::store()->put('health', 1, 5); Cache::store()->get('health')
Queue messenger transport Queue::size() vs threshold
Storage filesystem adapter Storage::disk()->put('.health', '1'); exists()
Search/HTTP custom checker Http::timeout(2)->get(...)

Each checker must have an explicit timeout. A health check that can hang is worse than no health check.

6. CI / deploy gate

Use the same endpoint as a post-deploy smoke test in your pipeline:

curl -fsS --max-time 5 https://app.example.com/health/ready || exit 1

This is where these packages earn their keep day-to-day: one contract shared by k8s, the load balancer, Uptime Kuma, and CI.

7. If you genuinely need the bundle

Run it only inside a Symfony application. If a Laravel app must consume it, put it behind an HTTP sidecar or a small Symfony service and have Laravel call /health/ready via Http::timeout(2). Do not attempt to register the bundle in config/app.php — Laravel has no bundle kernel.

Gotchas and Tips

  • Composer will “succeed” and nothing will happen. No Laravel auto-discovery means composer require is a no-op at runtime. Check composer why jpvdw86/symfony-health-check-bundle and vendor/ contents before assuming it’s wired up.
  • Watch what Symfony packages it drags in. A Symfony bundle commonly depends on symfony/framework-bundle, symfony/http-kernel, symfony/dependency-injection, and symfony/config. Installing it into Laravel can pull a large Symfony surface area for zero runtime benefit. Check composer.lock diff.
  • Project health signals are weak. One star, zero dependents, last release 2022-11-21. There is effectively no community maintenance, no security response process, and no ecosystem of forks. The MIT license means you can vendor and patch it, but plan to own it.
  • Pin the version and vendor the code if you depend on it. With a single release cadence and no dependents, upstream breakage or abandonment is a real risk. Copy the checkers into app/Health/ rather than depending on the package.
  • Health endpoints are an information leak. The JSON body may expose service names, hostnames, versions, and error strings. Either restrict /health/deep by IP/token or bind it to an internal listener. Never let APP_DEBUG=true output appear in the health response.
  • A throwing checker should not throw the endpoint. Wrap each check() in try/catch, record status: fail with a short message, and log the full exception. The aggregator should always produce a report.
  • Timeouts everywhere. Set connect + total timeouts on DB, Redis, and HTTP. Default PDO/Redis timeouts are often effectively “forever,” which is how a health endpoint takes down your probe fleet.
  • Don’t check downstream services in liveness. As above — only readiness. Also consider excluding flaky third-party APIs from the orchestrator-facing check and exposing them only in /health/deep.
  • Symfony config quirks (if you do run it in Symfony): the config tree is strict — unknown keys throw at cache warmup. After changing config/packages/*.yaml, run bin/console cache:clear. Use bin/console debug:container --tag=<checker-tag> to verify your custom checker is actually registered, and bin/console debug:router to confirm the route was imported.
  • Extension points: custom checker (implement the interface, tag the service), custom aggregator/response formatter, and per-checker enable/disable via config. If the package doesn’t expose one of these in Configuration.php, don’t assume it exists — decorate the service instead.
  • Debugging checklist: curl -i to see the status code (not just the body), check the app log for swallowed checker exceptions, verify the tag with debug:container, and test with the dependency deliberately stopped (e.g., docker compose stop redis) to confirm you actually get a 503.
  • Laravel-native alternative: spatie/laravel-health and Laravel’s built-in php artisan about cover most of this with active maintenance and first-class Laravel integration. For most Laravel teams, that is the correct day-to-day tool; this bundle is best used as a design reference or in a genuinely Symfony codebase.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings