Database schema & key types
Four tables back the package:
| Table | Columns | Notes |
|---|---|---|
health_checks | id, notifiable_type + notifiable_id, health_check, frequency (nullable), max_attempts, decay_minutes, consecutive_failures, consecutive_successes, tags (json), meta (json), timestamps, deleted_at | One row per scheduled check per owner. A null frequency marks an on-demand row seeded by run() — the scheduler never queues it. Soft deletes. |
alerts | id, notifiable_type + notifiable_id, health_check_id, status, escalation_level, message (text), meta (json), triggered_at, recovered_at, open_slot, timestamps, deleted_at | One row per incident — recovered_at is null while it is open. open_slot is 1 while open and null once recovered; a unique (health_check_id, open_slot) index admits one open alert per check. Soft deletes; indexed on owner + health check. |
alert_silences | id, key, notifiable_type + notifiable_id (nullable), reason, starts_at, ends_at, timestamps | Mute records: a check key, a tag or *, optionally scoped to one owner. Null starts_at means active immediately; null ends_at means until unmuted. |
health_check_runs | id, health_check_id, status, duration_ms, message (text), meta (json), ran_at | One immutable row per executed run, no timestamps. Indexed on health check + ran_at. |
alerts and health_check_runs carry a foreign key onto health_checks that cascades on delete — which is why health_checks is published first. HealthCheck and Alert use soft deletes, so the cascade applies when a row is force-deleted.
Owner key type
Owners are polymorphic (notifiable_type + notifiable_id), so any Eloquent model can own health checks. key_type types the notifiable_id column on health_checks, alerts and alert_silences:
| key_type | Notifiable columns | Use when your owners… |
|---|---|---|
bigint | morphs() — unsignedBigInteger id | use Laravel’s default auto-incrementing keys (the default) |
uuid | uuidMorphs() | use HasUuids |
ulid | ulidMorphs() | use HasUlids |
# Set before you run the migrations — the notifiable columns are typed from it
ALERTS_KEY_TYPE=uuidAll your owner models must share one key type. The value is case-insensitive; an absent or blank key means bigint, and an unrecognized value throws InvalidConfigurationException when the migrations run instead of falling back. The package’s own tables always keep auto-incrementing ids.
Where options live
Per-monitor options that have no column — failAfter, recoverAfter, timeout, channel routing and the escalation policy — are stored inside the row’s meta json under reserved keys (see Scheduling checks), next to any meta of your own.
On-demand rows and open alerts
Running a check now for an owner that has no schedule for it seeds an on-demand row with a null frequency. It keeps that owner’s counters, history and alerts for the check between manual runs, but the scheduler never queues it (see Running checks). On alerts, the unique (health_check_id, open_slot) index guarantees at most one open alert per check, even when two failing runs overlap. Run and alert messages are text columns, stored up to 1000 characters.
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.