|
| 1 | +--- |
| 2 | +"@objectstack/service-automation": minor |
| 3 | +--- |
| 4 | + |
| 5 | +feat(automation): durable run history — every terminal run leaves a queryable record with its failure reason |
| 6 | + |
| 7 | +Automation runs were observable **only in memory**: the engine kept the last N |
| 8 | +`ExecutionLogEntry` records in a ring buffer, so "did this flow run, and why did |
| 9 | +it fail?" could not be answered after a process restart (or once the buffer |
| 10 | +evicted the entry), and a failed run surfaced no reason at all. This was the |
| 11 | +biggest silent-trust gap for anyone authoring automations — a flow could stop |
| 12 | +firing or start failing with nothing durable to inspect. |
| 13 | + |
| 14 | +`sys_automation_run` — previously the ADR-0019 store for *live suspended* runs |
| 15 | +only — becomes a durable **run-history** table. On every terminal run the engine |
| 16 | +mirrors a row through the `SuspendedRunStore` (`recordTerminal`): `status` |
| 17 | +(`completed` / `failed`), `finished_at`, `duration_ms`, and, for a failure, the |
| 18 | +`error` message a designer needs to fix it. `listRuns()` merges this durable |
| 19 | +history with the in-memory buffer (in-memory wins on id, newest-first) so the |
| 20 | +Studio "Runs" surface shows runs that predate the current process. |
| 21 | + |
| 22 | +The design is **safe and additive**. Terminal history rows use a `run_`-prefixed |
| 23 | +id, disjoint from live suspended runs (which key on the raw `runId` with |
| 24 | +`status: 'paused'`), so the suspend save/load/delete/list path is untouched and |
| 25 | +resume sweeps (`list()` filters `status: 'paused'`) never see history rows. |
| 26 | +Persisting is **best-effort and fire-and-forget** — a history-write failure is |
| 27 | +logged and swallowed, never breaking the run that produced it. New object fields |
| 28 | +(`finished_at`, `duration_ms`, `error`) are all optional and the `status` enum |
| 29 | +gains `running` / `completed` / `failed` alongside the existing `paused`. |
| 30 | + |
| 31 | +Verified end-to-end on a clean showcase instance: a schedule-triggered flow and |
| 32 | +seven task-completion flows each left durable `completed` rows; a genuinely |
| 33 | +failing flow (`showcase_resilient_sync`) left a `failed` row carrying its |
| 34 | +`try_catch` failure reason; a live `paused` suspended run coexisted without |
| 35 | +collision; and after a full process restart the `failed` row — reason intact — |
| 36 | +was still queryable via `/api/v1/data/sys_automation_run`. New `run-history.test.ts` |
| 37 | +covers completed/failed persistence, read-across-restart, and best-effort isolation. |
0 commit comments