From 3912b91bc4b8af0263ab50d5fdbb72237ddb234d Mon Sep 17 00:00:00 2001 From: Crimson Date: Fri, 7 Aug 2026 06:15:38 +0500 Subject: [PATCH] fix(daemon): record the docker events failure, not only the recovery [P2] The outer loop called set_err and dropped the result, so no docker_events=error line was ever written while the reconnect did write docker_events=recovered. The events log could therefore show a recovery from a failure it had never recorded, which contradicts its documented contract of holding transitions in both directions. last_action.state was correct throughout - this was the journal only. Both branches now build the reason and share one report, matching the wording the periodic reconcile already uses. --- traffic_core/src/daemon.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/traffic_core/src/daemon.rs b/traffic_core/src/daemon.rs index aad3c55..aaef88f 100644 --- a/traffic_core/src/daemon.rs +++ b/traffic_core/src/daemon.rs @@ -89,21 +89,15 @@ pub fn run(cfg: Config) -> anyhow::Result<()> { let events_state = state.clone(); thread::spawn(move || { loop { - match docker_events_loop(&events_cfg, &events_state) { - Ok(()) => { - set_err( - &events_state, - "docker_events", - "docker events stream ended, restarting".to_string(), - ); - } - Err(e) => { - set_err( - &events_state, - "docker_events", - format!("docker events loop crashed: {e}"), - ); - } + let reason = match docker_events_loop(&events_cfg, &events_state) { + Ok(()) => "docker events stream ended, restarting".to_string(), + Err(e) => format!("docker events loop crashed: {e}"), + }; + // The reconnect writes its recovery, so the failure has to be written too. The + // journal is documented as holding transitions in both directions, and dropping + // this one left it showing a recovery from a failure it never recorded. + if set_err(&events_state, "docker_events", reason.clone()) { + append_event(&format!("docker_events=error error=\"{reason}\"")); } thread::sleep(Duration::from_secs(10)); }