From df8c1acb2920579d0248156d410757565fa5c42f Mon Sep 17 00:00:00 2001 From: BYTES-TECHES Date: Wed, 27 May 2026 23:29:52 +0200 Subject: [PATCH] feat: add graceful shutdown summary for active sessions --- src/server/debug_server.rs | 60 +++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/src/server/debug_server.rs b/src/server/debug_server.rs index c6d0fdaa..9769a0c8 100644 --- a/src/server/debug_server.rs +++ b/src/server/debug_server.rs @@ -154,6 +154,7 @@ impl DebugServer { } _ = self.shutdown.notified() => { info!("Shutting down debug server"); + self.log_shutdown_summary(); drop(listener); break; } @@ -260,22 +261,31 @@ impl DebugServer { let mut _heartbeat_timer = None; loop { - let next_message = if let Some(timeout) = idle_timeout { - match tokio::time::timeout( - std::time::Duration::from_millis(timeout as u64), - rx_in.recv(), - ) - .await - { - Ok(res) => res, - Err(_) => { - warn!("Idle timeout reached for connection"); - let _ = send_msg(DebugMessage::response(0, DebugResponse::Disconnected)); - return Ok(()); + let next_message = tokio::select! { + msg = async { + if let Some(timeout) = idle_timeout { + match tokio::time::timeout( + std::time::Duration::from_millis(timeout as u64), + rx_in.recv(), + ) + .await + { + Ok(res) => res, + Err(_) => { + warn!("Idle timeout reached for connection"); + let _ = tx_out.send(DebugMessage::response(0, DebugResponse::Disconnected)); + None + } + } + } else { + rx_in.recv().await } + } => msg, + _ = self.shutdown.notified() => { + info!("Shutdown signal received during active connection"); + self.shutdown.notify_one(); + break; } - } else { - rx_in.recv().await }; let line = match next_message { @@ -1496,6 +1506,8 @@ impl DebugServer { self.last_disconnect = Some(std::time::Instant::now()); } + reader_handle.abort(); + Ok(()) } } @@ -1753,6 +1765,26 @@ mod tests { assert_eq!(server.token, Some(token)); } + #[test] + fn test_shutdown_summary_output() { + let mut server = DebugServer::new( + "127.0.0.1".to_string(), + None, + None, + None, + None, + Vec::new(), + false, + Vec::new(), + Vec::new(), + ) + .unwrap(); + + // Inject fake state to verify no panics during formatting + server.contract_wasm = Some(vec![0x00, 0x61, 0x73, 0x6d]); + server.log_shutdown_summary(); + } + #[test] fn test_server_rejects_partial_tls_configuration() { let result = DebugServer::new(