ANW-45 Serve: exit nonzero when the supervisor tree fails to start

Hydra's Application::run logs a start failure and returns normally, so
serve exited 0 after the tree never came up. systemd read that as a clean
start and Restart=on-failure never retried; anwesen was unreachable on ap
for 12 hours with NRestarts=0.

Anwesen carries a started flag that start() sets once the supervisor is
up, and main exits 1 when it is still false after run() returns.

Assumed the flag is the only seam available: run() consumes self and
returns (), so the Err is not observable at the call site. Flag if a newer
hydra exposes the result.
This commit is contained in:
Andreas Brenner 2026-07-29 22:22:12 +03:00
parent d6261bd5f9
commit 30bca24b5c
3 changed files with 56 additions and 3 deletions

View file

@ -6,6 +6,7 @@
mod cli;
use std::sync::Arc;
use std::sync::atomic::Ordering;
use anwesen::app::Anwesen;
use anwesen::doctor;
@ -46,12 +47,22 @@ fn main() -> Result<()> {
telemetry = telemetry.is_some(),
"anwesen serve: starting supervisor tree"
);
let app = Anwesen::new(args.vault, args.bind, telemetry.clone());
let started = app.started.clone();
// Blocks until the supervisor exits (SIGTERM / SIGINT / crash).
Anwesen::new(args.vault, args.bind, telemetry.clone()).run();
app.run();
// Flush and shut down exporters after the server loop returns.
if let Some(telemetry) = telemetry {
telemetry.shutdown();
}
// `run` returns normally whether the tree came up or never
// started, so a failed start would otherwise look like a clean
// exit and systemd's `Restart=on-failure` would not retry
// (ANW-45). Exit nonzero when the tree never came up.
if !started.load(Ordering::Acquire) {
tracing::error!("anwesen serve: supervisor tree failed to start");
std::process::exit(1);
}
}
Command::Doctor(args) => {
init_logging(args.log_level);