From 2962b4e3f865fc294238333401268758efd6d11b Mon Sep 17 00:00:00 2001 From: junderw Date: Sun, 31 May 2026 11:35:25 +0900 Subject: [PATCH] electrum: force exit if graceful shutdown exceeds 5 seconds Slow or zombie TCP clients can keep peer connection threads alive, blocking the RPC drop/join on shutdown indefinitely. Replace the shutdown thread-logging loop with a watchdog that forcibly exits the process if graceful shutdown has not completed within 5 seconds. --- src/bin/electrs.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/bin/electrs.rs b/src/bin/electrs.rs index 0c649355..1bb97daa 100644 --- a/src/bin/electrs.rs +++ b/src/bin/electrs.rs @@ -122,17 +122,25 @@ fn run_server(config: Arc) -> Result<()> { if let Err(err) = signal.wait(Duration::from_millis(config.main_loop_delay), true) { info!("stopping server: {}", err); - electrs::util::spawn_thread("shutdown-thread-checker", || { - let mut counter = 40; - let interval_ms = 500; - - while counter > 0 { + // Watchdog: give the graceful shutdown ~5 seconds to close all TCP + // connections. If it hasn't completed by then (e.g. clients holding + // sockets open with slow/zombie connections), force the process to + // exit so we don't hang indefinitely. + electrs::util::spawn_thread("shutdown-watchdog", || { + let timeout = Duration::from_secs(5); + let interval = Duration::from_millis(500); + let mut elapsed = Duration::ZERO; + + while elapsed < timeout { electrs::util::with_spawned_threads(|threads| { debug!("Threads during shutdown: {:?}", threads); }); - std::thread::sleep(std::time::Duration::from_millis(interval_ms)); - counter -= 1; + std::thread::sleep(interval); + elapsed += interval; } + + error!("graceful shutdown timed out after 5 seconds, forcing exit"); + process::exit(0); }); rest_server.stop();