Flap detection & recovery confirmation
failAfter(n) requires n consecutive failures before an alert is opened and HealthCheckFailed and notifications fire, killing flapping noise. recoverAfter(n) mirrors it: an alert stays open until n consecutive OK results confirm recovery. Both default to 1 — open and close immediately:
Health::for($team)->monitor(PaymentGatewayCheck::class)
->everyMinute()
->failAfter(3) // alert on the 3rd consecutive failure
->recoverAfter(2) // close after 2 consecutive OKs
->save();How the counters work
- Per-monitor counters live on the health_checks row: consecutive_failures and consecutive_successes.
- A warning or failed result increments consecutive_failures and resets consecutive_successes. An ok result does the opposite.
- A skipped result touches neither counter.
- Below the threshold the run is still recorded in history — only the alert side effects are gated. The status report shows ok until an alert actually opens.
- When recovery closes an alert, consecutive_successes resets to 0.
- Counters are written relatively (failures = failures + 1) and re-read, so two overlapping runs never lose an increment and silently defer an alert.
- Values below 1 clamp to 1.
A worked example
With failAfter(3) and recoverAfter(2): runs one and two fail and are recorded, but nothing else happens. Run three fails and opens the alert, fires HealthCheckFailed and notifies. Every further failing run fires HealthCheckFailed again; without an escalation policy it also notifies again, limited by the throttle. Once the service is back, the first OK leaves the alert open and the second closes it and fires HealthCheckRecovered.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.