Show each webhook's activity in the webhook list (closes #394)
check / check (push) Failing after 1m17s

Each entry in the webhook list now shows when the webhook's last event
arrived, or "No events yet", and how many of its deliveries failed in
the last 24 hours, in red when that is not zero. The entrypoint and
target counts say how many are inactive.

The figures come from the statistics pane's own reads: the event totals
row, which now also gives the event count instead of counting every
stored event, and the pane's query over the deliveries finished in the
last 24 hours. A webhook whose event database cannot be read says so in
its entry rather than showing zeros.

Model: opus-5-5
This commit is contained in:
2026-10-02 04:48:17 +00:00
parent 803a94be37
commit 465d95b7ef
4 changed files with 376 additions and 27 deletions
+10 -2
View File
@@ -1752,7 +1752,7 @@ retries) is individually logged for full observability.
#### EventTotals and TargetTotals
Running counts in each event database, read by the statistics pane at the
top of the webhook page. `EventTotals` is one row:
top of the webhook page and by the webhook list. `EventTotals` is one row:
| Field | Type | Description |
| ---------------- | --------- | ----------- |
@@ -1784,6 +1784,14 @@ target. Its failure percentage for a window is the deliveries that became
`failed` in it out of all that became `delivered` or `failed` in it, and
a dash when none did.
The webhook list at `/hooks` reads the same figures for each webhook: its
events within retention and its last event from `EventTotals`, and its
deliveries that failed in the last 24 hours with the pane's query. It
opens each webhook's event database once (the handle stays open) and runs
those two queries there, so its cost grows with the number of webhooks
and, for each, with the deliveries that finished in the last 24 hours,
never with the events stored.
#### Event-tier indexes
These indexes on the per-webhook event databases are declared in the model
@@ -1791,7 +1799,7 @@ tags, so `AutoMigrate` creates them on a fresh database:
| Table | Columns | Serves |
| ------------------ | --------------------------- | ------ |
| `deliveries` | `status`, `deleted_at`, `finished_at`, `target_id` | Startup recovery, the retry and pending sweeps every 60 seconds and the queue-depth sampler every 30 seconds, which select deliveries by status, and the webhook page's statistics, which count each target's deliveries by status and when they finished |
| `deliveries` | `status`, `deleted_at`, `finished_at`, `target_id` | Startup recovery, the retry and pending sweeps every 60 seconds and the queue-depth sampler every 30 seconds, which select deliveries by status, and the webhook page's statistics and the webhook list, which count each target's deliveries by status and when they finished |
| `deliveries` | `event_id`, `deleted_at` | The event log, which loads each event's deliveries, and retention, which counts and deletes the deliveries of expired events |
| `delivery_results` | `delivery_id`, `deleted_at` | The event log, which loads the attempts of a page's deliveries, and retention, which deletes the attempts of expired events |
| `events` | `deleted_at`, `created_at` | The webhook page's statistics, which count recent events |