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.
Architecture fit. A health-check endpoint is an edge concern: a thin route-plus-registry adapter with no domain coupling, no data ownership, and no service-boundary implications. That is inherently good fit — adopting, wrapping, or replacing it is contained to a single controller and a handful of probe classes. The complication is the artifact itself. The description bills this as a Laravel health-check package, but the package name (-bundle), the symfony/framework-bundle dependency, and the DependencyInjection/ + *Bundle.php layout all indicate a Symfony bundle. Nothing here registers with Laravel's service container, route table, or config publisher. For a TPM this is the single decision-critical finding: the spec sheet and the artifact disagree, and the artifact wins. It downgrades the proposition from "drop-in Laravel dependency" to "reusable probe classes and a reference wire format," which is a materially different (and much smaller) value claim.
Integration feasibility. Economically trivial to trial and trivial to abandon: MIT licensed, small surface area, zero transitive ecosystem gravity. The cost of a failed spike is measured in hours, not sprints, which is exactly the risk profile that justifies saying yes to an evaluation. The counterweight is zero dependents and a single star — there is no production evidence anywhere in the ecosystem. If we adopt, we are the first serious adopter, meaning our integration effort is simultaneously the project's QA effort. That is an acceptable trade for an edge concern if it is timeboxed and wrapped; it is not acceptable if it becomes load-bearing infrastructure by accident.
Technical risk.
| Risk | Severity | TPM read |
|---|---|---|
| Claimed Laravel support vs. Symfony packaging | High | Determines whether this is a half-day reuse exercise or a multi-day bridge. Gate the decision on this alone. |
| Single maintainer, no bus factor | High | Assume volunteer cadence. Plan for a fork, not a support relationship. |
| Zero production usage (1 star, 0 dependents) | High | We absorb all edge-case discovery. Budget review time as real engineering cost. |
| Unauthenticated endpoint by default | Medium | Health routes are a classic information-disclosure surface (dependency names, hostnames, version fingerprints). |
| Version drift against PHP/Laravel | Medium | Small packages often declare loose or absent constraints and have no CI matrix. |
| Dependency-tree hygiene | Medium | Small maintainers rarely run automated audits; we own that check. |
| License | Low | MIT is clean for commercial use, forking, and vendoring. |
Key questions.
Stack fit. Our runtime is Laravel; the package is Symfony. Two honest options exist. Option one: consume the check classes as a standalone library, registering them behind a Laravel service provider we write ourselves — viable only if the probes are free of Symfony Kernel/ContainerAware coupling, which the spike must confirm. Option two: treat the package as a reference implementation — read its aggregation semantics, status-code logic, and JSON shape, and reproduce them natively. Given the maturity signals, option two is the presumptive default and option one is the upside case.
Migration path. Do not let the application depend on the package's namespace. Define an internal contract first — a HealthCheck interface plus a HealthController that assembles a status payload from an array of checks — and let any package implementation sit behind that seam. Swapping to a hand-rolled controller, to spatie/laravel-health, or to our own probes with Symfony-derived logic then becomes a one-file change. This collapses most of the adoption risk for roughly a day of engineering and is the single highest-leverage move available here.
Compatibility and build-vs-buy. Benchmark before committing: a native /health route covering database, cache, and disk is 20–50 lines and eliminates an unproven third-party dependency entirely. Adopt the package only if its probe set or aggregation behavior is materially richer than what we would write in an afternoon — and be honest that "we would have to write it anyway" is the likely verdict for the framework integration layer. Whatever the outcome, pin to a commit SHA or exact tag; no floating constraints on an unmaintained package.
Sequencing.
composer.json and the service provider. Install on a scratch branch, hit each endpoint, record payload shape, latency, and whether the probes are portable to Laravel. Produce a written go/no-go.HealthCheck seam and a native fallback endpoint regardless of the spike outcome. This is not wasted work under either decision.livenessProbe/readinessProbe or ALB target-group checks, with distinct liveness and readiness semantics.Maintenance. Plan to own the code. The correct posture is "vendored dependency with periodic manual review," not "upstream-maintained dependency with a changelog we track." Budget a recurring line item: a quarterly compatibility check against current PHP/Laravel, and a standing fork-ready stance (MIT permits it). Pin the exact version; never let this float.
Support. No support channel with an SLA, no security disclosure process, best-effort volunteer issue response. Any production incident traced here is resolved by our engineers reading the source — so the source must remain small enough to read. Verify that as an explicit spike criterion, not an assumption.
Scaling. Probe traffic is high-frequency by design (every few seconds × N replicas), so cost is dominated by probe behavior rather than request volume. Two controls: cache expensive checks with a short TTL so fifty pods don't issue fifty database round-trips per interval, and exclude the endpoint from access logs and APM tracing or it will dominate telemetry volume and skew latency dashboards. Avoid readiness checks that fan out to shared downstreams, which amplifies load precisely when the system is already degrading.
Failure modes. The dangerous one is correlated failure: a readiness check asserting shared-dependency health (a common database or cache) marks every replica unhealthy at once, and the orchestrator restarts the entire fleet — converting a dependency blip into a self-inflicted outage. Liveness must assert only process responsiveness; readiness may assert dependency health but needs aggressive timeouts and must fail closed on timeout rather than hang. Secondary modes: an open endpoint disclosing dependency topology and version fingerprints, and unhandled exception paths returning 500s that infrastructure reads as "unhealthy."
Ramp-up. Low. One engineer, roughly half a day to spike and one to two days to productionize behind the seam. The real cost is not learning the package — it is the review overhead of admitting an unproven dependency into the runtime: security sign-off, dependency-tree audit, and an explicit decision record. Framed as a timeboxed, wrapped pilot for a non-critical edge concern, the operational risk is proportionate. Framed as a standard third-party dependency, it is not — and that framing is the TPM's call to make.
How can I help you explore Laravel packages today?