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

Health Check Bundle Laravel Package

lgarret/health-check-bundle

Health Check Bundle adds configurable health-check endpoints to PHP applications, letting load balancers, Kubernetes probes, and uptime monitors verify service availability and dependency status. Simple setup, framework integration, and extensible checks for production monitoring.

View on GitHub
Deep Wiki
Context7

Getting Started

Calibrate expectations before installing anything. Despite the "Laravel" framing in the description, the artifact is named lgarret/health-check-bundle, ships with a -bundle suffix, and (per the Laravel developer assessment) uses the Symfony DependencyInjection/ + *Bundle.php layout with a symfony/framework-bundle dependency. Start by reading composer.json and src/ to determine whether this is (a) a genuine Laravel package with a service provider and publishable config, (b) a Symfony bundle with any framework-agnostic check classes you can lift, or (c) a "bundle" that happens to also register Laravel bindings. That answer determines your entire integration path.

Where to look first, in order:

  1. composer.json — framework constraints, autoloading, PHP version floor, and whether symfony/* or laravel/framework / illuminate/* appear as dependencies.
  2. src/ — locate the check interface and concrete checks (database, cache, disk, queue, HTTP downstream). These are the reusable parts regardless of framework.
  3. DependencyInjection/Configuration.php (or config/*.php if it's Laravel-native) — reveals the config schema you'd mirror in config/health.php.
  4. README — the JSON contract and HTTP status codes (usually 200 for healthy, 503 for degraded) your probes will consume.

Minimal first use case in a Laravel app. Whether or not you ultimately adopt the bundle, expose the same wire contract so monitoring, load balancers, and k8s probes are decoupled from the implementation:

// routes/web.php
use Illuminate\Support\Facades\Route;

Route::get('/health', function () {
    $checks = [
        'database' => rescue(fn () => DB::select('select 1') ? 'ok' : 'fail', 'fail'),
        'cache'    => rescue(fn () => Cache::put('hc', 1, 5) ? 'ok' : 'fail', 'fail'),
        'disk'     => rescue(fn () => disk_free_space(storage_path()) > 100_000_000 ? 'ok' : 'fail', 'fail'),
    ];

    $ok = !in_array('fail', $checks, true);

    return response()->json(
        ['status' => $ok ? 'ok' : 'fail', 'checks' => $checks],
        $ok ? 200 : 503
    );
});

That ~20-line route typically covers the same checks this package advertises. If that satisfies your need, treat the bundle as a pattern reference and stop. If you require its aggregation semantics, pluggable registry, or timing data, proceed to Implementation Patterns.

Recommended first spike (≈2 hours): clone into a scratch branch, inspect the check interface, and write a throwaway script that instantiates one concrete check (e.g., the database check) statically. If the check class has no framework coupling in its constructor, you can reuse it directly inside a Laravel controller and skip the Symfony plumbing entirely.

Implementation Patterns

Three realistic patterns, ordered from lowest to highest integration effort.

Pattern A — Lift the check classes into your own Laravel route (recommended for Laravel shops). Treat the bundle as a library of probe implementations, not a framework integration. Wrap the framework-agnostic check classes in a thin controller you control:

namespace App\Http\Controllers;

use App\Health\CheckInterface; // your own interface

class HealthController
{
    public function __construct(private iterable $checks) {}

    public function __invoke()
    {
        $results = [];
        $healthy = true;

        foreach ($this->checks as $name => $check) {
            $start = microtime(true);
            try {
                $ok = $check->run();
            } catch (\Throwable $e) {
                $ok = false;
                logger()->warning("health.{$name} failed", ['e' => $e->getMessage()]);
            }
            $results[$name] = [
                'status'  => $ok ? 'ok' : 'fail',
                'seconds' => round(microtime(true) - $start, 4),
            ];
            $healthy = $healthy && $ok;
        }

        return response()->json(
            ['status' => $healthy ? 'ok' : 'fail', 'checks' => $results],
            $healthy ? 200 : 503
        );
    }
}

Register the checks you want from the package in a service provider, and you get its probe logic while keeping routing, config, and DI entirely inside Laravel's idioms. This is the seam recommended by both upstream assessments: adopt the library, control the contract.

Pattern B — Separate liveness vs. readiness routes. Health endpoints should split. Liveness proves the process is up (never touches dependencies); readiness proves dependencies are reachable. Conflating them causes the classic "shared DB blip restarts the whole fleet" outage.

Route::get('/health/live',  fn () => response()->json(['status'=>'ok'], 200));

Route::get('/health/ready', function () {
    // only cheap, cached checks here with hard timeouts
});

If you use the bundle (in a Symfony sidecar) for the readiness probe, keep /live local and dependency-free.

Pattern C — Sidecar Symfony app scraped alongside your Laravel app. If you operate a non-Laravel service anyway, run the bundle where it's natively supported and let your orchestrator probe the sidecar. Your Laravel app remains untouched; the health endpoint is provided by a process the bundle was designed for. This is the lowest-adaptation path if a Symfony component is already in your estate.

Day-to-day operational patterns:

  • Cache probe results with a short TTL (Cache::remember('health.db', 5, ...)). At 50 pods × 1 probe/5s, a naive DB round-trip per probe is tens of thousands of extra queries per hour.
  • Restrict the ready route to orchestrator/ALB CIDRs or require a bearer token — health endpoints are classic reconnaissance surfaces (versions, hostnames, dependency topology).
  • Exclude /health/* from access logging and APM tracing, or it will dominate your log volume and skew latency percentiles.
  • Wrap every check in a timeout, not just try/catch. A check that hangs on a dead Redis is worse than one that fails fast.
  • Register custom checks behind a CheckInterface you define (run(): bool, name(): string, timeout(): float); adapter classes that delegate to the package's checks keep the seam narrow so you can swap implementations (spatie/laravel-health, a hand-rolled probe) in one file.

Gotchas and Tips

Framework mismatch is the #1 risk. The -bundle suffix is not cosmetic in Symfony-land. Verify that src/ doesn't reference Kernel, ContainerAwareInterface, or EventDispatcher before you plan any Laravel integration. If it does, you are not "one composer require away" — you're writing an adapter.

Zero dependents and one star mean you are the QA. There is no production evidence anywhere. Budget a source read: it should be small enough that one engineer can audit it in under an hour. If it isn't, that's a reason to decline adoption on its own.

Pin to a tag or commit SHA, not a constraint. With a single-maintainer project and no changelog cadence, ^1.0 can silently become whatever the maintainer pushed last Tuesday. Lock the version and record the SHA in your decision record.

The endpoint is world-readable by default. Health routes typically answer unauthenticated GETs and leak: which database you use, whether Redis is up, disk mount paths, and (via version strings in error bodies) framework/PHP fingerprints. Gate the ready route and never return stack traces — log them, don't serialize them.

A throwing check must not return 500. Many health packages catch exceptions internally; if yours doesn't, an uncaught PDOException yields a 500, which some load balancers treat differently from 503 (and some APM tools auto-alert on it). Wrap every check in try/catch and convert failures to a clean 503 with a fail payload.

Correlated failure is the dangerous mode. A readiness check that asserts the health of a shared database will mark every replica unhealthy simultaneously when the DB hiccups, and the orchestrator will restart the entire fleet. Liveness must never touch dependencies. Readiness may, but must have aggressive timeouts and fail closed.

Config is likely a Symfony tree, not a Laravel one. If there's a DependencyInjection/Configuration.php, read it to learn what's tunable (route path, middleware, failure threshold, check set), then mirror those knobs in a config/health.php you control. Don't try to publish the bundle's config into Laravel — it will not bind.

composer.json version constraints are often loose in small packages. Check the PHP and framework floors against your app's runtime. If the bundle declares php: ^8.0 but uses features from 8.2, your CI will find it before your monitor does.

Extension points worth verifying early: (a) can you disable built-in checks individually? (b) can you reorder or weight them? (c) does the response format expose per-check timing? (d) is there a hook/event for post-aggregation? If the answer to (a) is "no," the package will probe things you don't own, which is a frequent source of false positives in shared infrastructure.

Fallback plan must be written down. Given the maturity signals (1 star, 0 dependents, single maintainer), treat this as a timeboxed pilot with an exit criterion. The realistic posture is "vendored reference implementation with a quarterly review," not "upstream-maintained dependency." The 20-line route in Getting Started is your fallback; keep it in the decision record so nobody has to rediscover it during an incident.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core