fix(server): shut down through fx so buffered reports flush (closes #22)
check / check (push) Failing after 0s

The server ran os.Exit at the end of its own goroutine, which raced fx's
teardown and could kill the process before reportbuf's OnStop flushed the
buffer — losing up to a full flush window of telemetry on every restart,
silently and with exit 0. The server now requests shutdown through
fx.Shutdowner, so fx runs every OnStop in dependency order.

The http.Server is built synchronously in OnStart before the serving
goroutine starts, so shutdown can no longer race or nil-deref it; the
field is never written and read from two goroutines without a
happens-before edge. A listen failure now exits non-zero via
fx.ExitCode(1). reportbuf's OnStop is guarded by sync.Once. writeTimeout
now exceeds the chi per-request budget, with a comment, so that budget is
reachable. Dead startupTime, exitCode, and cancelFunc fields are gone.

A new test buffers a report and asserts it reaches disk after the fx
lifecycle stops.

Model: opus-4-8
This commit is contained in:
2026-09-21 12:49:59 +00:00
parent f7c7f92e27
commit dd762ce759
5 changed files with 154 additions and 100 deletions
+9
View File
@@ -22,6 +22,15 @@ files, so merging it also closes most compliance gaps.
# Completed Steps
- 2026-09-21: shutdown lifecycle correctness. The process now shuts down through
fx instead of `os.Exit`, so every component's `OnStop` runs and buffered
reports are flushed to disk on `SIGTERM` — previously a full flush window of
telemetry was silently lost on every restart. The `http.Server` is now built
before its serving goroutine starts, so shutdown can no longer race or
nil-deref it; a listen failure exits non-zero via `fx.Shutdowner`; `reportbuf`
`OnStop` is idempotent; and `writeTimeout` now exceeds the chi per-request
budget so that budget is actually reachable. Dead `startupTime`, `exitCode`,
and `cancelFunc` fields were removed
- 2026-08-10: every interactive control now meets the 44x44 CSS px minimum tap
target (`.pin-btn`, `#interval-select`, the debug-log label and, on narrow
viewports, `#pause-btn`). The pin button's hit area grows via matching