fix(gateway): recover watchdog after transient loop stalls - #67051
fix(gateway): recover watchdog after transient loop stalls#67051StellarisW wants to merge 1 commit into
Conversation
Related to merged #66946: that work added systemd watchdog wiring, while this PR fixes the distinct residual case where one transient late tick permanently stops watchdog feeds. |
|
Thanks for the focused recovery fix. The premise is verified on current Problems
Suggested changes
Automated hermes-sweeper review. |
89be2d1 to
c4babe0
Compare
|
Addressed in
Final local validation: 23 focused watchdog tests, 113 gateway config tests, 9,646 gateway tests, docs diagram lint (364 files), Docusaurus English/zh-Hans build, Ruff/format/compile, and |
c4babe0 to
365134f
Compare
Summary
This fixes a residual failure mode in the opt-in systemd event-loop watchdog introduced by #66946:
degradedand keeps renewing the watchdog lease;healthyagain;WatchdogSecremains the hard-stop restart path.The PR has been rebased as one signed commit onto current
main(c896c09c42910c584c4c7d2325b58c14713ea42c). The rebase conflict came from main's later test-pruning pass; the resolution preserves that pruning and retains only the two behavior tests specific to this fix.Reproduction and root cause
With
gateway.systemd_watchdog_seconds > 0:WatchdogSec;Before this PR, the late callback permanently set
_unhealthy, returned withoutWATCHDOG=1, and caused_run()to exit. The event loop could recover in the same process, but the notifier never restarted, so systemd later restarted an otherwise progressing gateway.The classification was too coarse: a callback that runs late proves the loop resumed; it is different from a callback that never runs.
Behavioral contract
WATCHDOG=1WATCHDOG=1+STATUS=degradedWATCHDOG=1WATCHDOG=1+STATUS=healthyWatchdogSecImplementation
gateway/systemd_notify.py: adds the two-tick recovery state and keeps the notifier alive after a late callback.tests/gateway/test_systemd_notify.py: verifies the state transitions and injects a real transient loop stall.website/docs/user-guide/messaging/index.md: distinguishes late-but-resumed progress from a full no-callback stall.No new task, cadence, configuration key, dependency, public API, or persistence surface is added.
Validation
scripts/run_tests.sh: passed, 0 failed.ruff checkon both changed Python files: passed.ruff format --checkon both changed Python files: passed.git diff --check origin/main...HEAD: passed.origin/main..HEAD.365134f66990e2ac5f70bbb826247bbc271036f1: running after force-with-lease push.Local macOS note: the full
tests/gateway/test_systemd_notify.pyfile still contains main's pre-existing Linux abstract-socket test, whose skip condition accepts macOSAF_UNIXeven though macOS does not support Linux abstract socket addresses. Validation therefore selected the watchdog behavior tests directly; Linux CI runs the full file.Compatibility and risk
NOTIFY_SOCKET/ AF_UNIX gates.degraded; restart remains reserved for loss of progress through the fullWatchdogSecwindow.Scope and non-goals
Crash-safe in-flight session continuation remains separate in #67078.
Rollout and rollback
No migration is needed. Rollback is a single revert of signed commit
365134f66990e2ac5f70bbb826247bbc271036f1; there is no persisted state to clean up.Head integrity
StellarisW:codex/gateway-watchdog-recovery365134f66990e2ac5f70bbb826247bbc271036f1c896c09c42910c584c4c7d2325b58c14713ea42cInfographic
A callback that runs renews the lease; only callback absence leaves systemd to expire it. Two consecutive timely callbacks are required before degraded state returns to healthy.