From cf22c514de42482c786c9e4391344d22f581c35b Mon Sep 17 00:00:00 2001 From: KaiqiJinWow Date: Fri, 18 Sep 2026 00:34:55 +0000 Subject: [PATCH 1/3] fix: handle SIGTERM during graceful shutdown --- crates/lance-context-master/src/main.rs | 29 ++++++++++++++++++---- crates/lance-context-server/src/main.rs | 32 ++++++++++++++++++++----- python/tests/conftest.py | 7 ++++++ 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/crates/lance-context-master/src/main.rs b/crates/lance-context-master/src/main.rs index 611adeb1..62bea511 100644 --- a/crates/lance-context-master/src/main.rs +++ b/crates/lance-context-master/src/main.rs @@ -77,8 +77,29 @@ async fn main() { } async fn shutdown_signal() { - tokio::signal::ctrl_c() - .await - .expect("failed to install Ctrl+C handler"); - tracing::info!("Shutting down"); + #[cfg(unix)] + let signal = { + use tokio::signal::unix::{signal, SignalKind}; + + // Kubernetes and other process managers stop containers with SIGTERM. + let mut sigterm = + signal(SignalKind::terminate()).expect("failed to install SIGTERM handler"); + tokio::select! { + result = tokio::signal::ctrl_c() => { + result.expect("failed to install Ctrl+C handler"); + "SIGINT" + } + _ = sigterm.recv() => "SIGTERM", + } + }; + + #[cfg(not(unix))] + let signal = { + tokio::signal::ctrl_c() + .await + .expect("failed to install Ctrl+C handler"); + "Ctrl+C" + }; + + tracing::info!(signal, "Shutting down"); } diff --git a/crates/lance-context-server/src/main.rs b/crates/lance-context-server/src/main.rs index 9ca9f4fc..675b8ad6 100644 --- a/crates/lance-context-server/src/main.rs +++ b/crates/lance-context-server/src/main.rs @@ -85,15 +85,35 @@ async fn main() { .await .unwrap(); - // Connections have drained. Deterministically close resident rollout writers - // (whose `ShardWriter` background tasks need an explicit `close().await`) + // Connections have drained. Deterministically close every resident writer // before the runtime tears down. state.shutdown().await; } async fn shutdown_signal() { - tokio::signal::ctrl_c() - .await - .expect("failed to install Ctrl+C handler"); - tracing::info!("Shutting down"); + #[cfg(unix)] + let signal = { + use tokio::signal::unix::{signal, SignalKind}; + + // Kubernetes and other process managers stop containers with SIGTERM. + let mut sigterm = + signal(SignalKind::terminate()).expect("failed to install SIGTERM handler"); + tokio::select! { + result = tokio::signal::ctrl_c() => { + result.expect("failed to install Ctrl+C handler"); + "SIGINT" + } + _ = sigterm.recv() => "SIGTERM", + } + }; + + #[cfg(not(unix))] + let signal = { + tokio::signal::ctrl_c() + .await + .expect("failed to install Ctrl+C handler"); + "Ctrl+C" + }; + + tracing::info!(signal, "Shutting down"); } diff --git a/python/tests/conftest.py b/python/tests/conftest.py index 99d05500..6f6f8261 100644 --- a/python/tests/conftest.py +++ b/python/tests/conftest.py @@ -83,3 +83,10 @@ def server() -> Iterator[str]: proc.wait(timeout=10) log.seek(0) print(log.read().decode(errors="replace")) + if os.name == "posix": + # Popen.terminate sends SIGTERM on POSIX. A clean exit + # proves the server reached its graceful-shutdown path. + assert proc.returncode == 0, ( + "server did not handle SIGTERM gracefully " + f"(exit code {proc.returncode})" + ) From ee29af3f880d3bc5c7eeb8bae52e1af9419b3c78 Mon Sep 17 00:00:00 2001 From: KaiqiJinWow Date: Fri, 18 Sep 2026 06:31:21 +0000 Subject: [PATCH 2/3] refactor: clarify shutdown signal handling --- crates/lance-context-master/src/main.rs | 45 ++++++++++++------------- crates/lance-context-server/src/main.rs | 45 ++++++++++++------------- 2 files changed, 44 insertions(+), 46 deletions(-) diff --git a/crates/lance-context-master/src/main.rs b/crates/lance-context-master/src/main.rs index 62bea511..c53b5249 100644 --- a/crates/lance-context-master/src/main.rs +++ b/crates/lance-context-master/src/main.rs @@ -76,30 +76,29 @@ async fn main() { .unwrap(); } +#[cfg(unix)] async fn shutdown_signal() { - #[cfg(unix)] - let signal = { - use tokio::signal::unix::{signal, SignalKind}; - - // Kubernetes and other process managers stop containers with SIGTERM. - let mut sigterm = - signal(SignalKind::terminate()).expect("failed to install SIGTERM handler"); - tokio::select! { - result = tokio::signal::ctrl_c() => { - result.expect("failed to install Ctrl+C handler"); - "SIGINT" - } - _ = sigterm.recv() => "SIGTERM", - } - }; + use tokio::signal::unix::{signal as unix_signal, SignalKind}; - #[cfg(not(unix))] - let signal = { - tokio::signal::ctrl_c() - .await - .expect("failed to install Ctrl+C handler"); - "Ctrl+C" - }; + // Kubernetes and other process managers stop containers with SIGTERM. + let mut sigterm = + unix_signal(SignalKind::terminate()).expect("failed to install SIGTERM handler"); + + tokio::select! { + result = tokio::signal::ctrl_c() => { + result.expect("failed to install Ctrl+C handler"); + tracing::info!(signal = "SIGINT", "Shutting down"); + } + _ = sigterm.recv() => { + tracing::info!(signal = "SIGTERM", "Shutting down"); + } + } +} - tracing::info!(signal, "Shutting down"); +#[cfg(not(unix))] +async fn shutdown_signal() { + tokio::signal::ctrl_c() + .await + .expect("failed to install Ctrl+C handler"); + tracing::info!(signal = "Ctrl+C", "Shutting down"); } diff --git a/crates/lance-context-server/src/main.rs b/crates/lance-context-server/src/main.rs index 675b8ad6..6f7f30e0 100644 --- a/crates/lance-context-server/src/main.rs +++ b/crates/lance-context-server/src/main.rs @@ -90,30 +90,29 @@ async fn main() { state.shutdown().await; } +#[cfg(unix)] async fn shutdown_signal() { - #[cfg(unix)] - let signal = { - use tokio::signal::unix::{signal, SignalKind}; - - // Kubernetes and other process managers stop containers with SIGTERM. - let mut sigterm = - signal(SignalKind::terminate()).expect("failed to install SIGTERM handler"); - tokio::select! { - result = tokio::signal::ctrl_c() => { - result.expect("failed to install Ctrl+C handler"); - "SIGINT" - } - _ = sigterm.recv() => "SIGTERM", - } - }; + use tokio::signal::unix::{signal as unix_signal, SignalKind}; - #[cfg(not(unix))] - let signal = { - tokio::signal::ctrl_c() - .await - .expect("failed to install Ctrl+C handler"); - "Ctrl+C" - }; + // Kubernetes and other process managers stop containers with SIGTERM. + let mut sigterm = + unix_signal(SignalKind::terminate()).expect("failed to install SIGTERM handler"); + + tokio::select! { + result = tokio::signal::ctrl_c() => { + result.expect("failed to install Ctrl+C handler"); + tracing::info!(signal = "SIGINT", "Shutting down"); + } + _ = sigterm.recv() => { + tracing::info!(signal = "SIGTERM", "Shutting down"); + } + } +} - tracing::info!(signal, "Shutting down"); +#[cfg(not(unix))] +async fn shutdown_signal() { + tokio::signal::ctrl_c() + .await + .expect("failed to install Ctrl+C handler"); + tracing::info!(signal = "Ctrl+C", "Shutting down"); } From 1590fb1b826929df41c185f63f9df799921d660a Mon Sep 17 00:00:00 2001 From: KaiqiJinWow Date: Mon, 21 Sep 2026 22:25:57 +0000 Subject: [PATCH 3/3] refactor: clarify shutdown signal waiter --- crates/lance-context-master/src/main.rs | 6 +++--- crates/lance-context-server/src/main.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/lance-context-master/src/main.rs b/crates/lance-context-master/src/main.rs index c53b5249..6fa3c1a6 100644 --- a/crates/lance-context-master/src/main.rs +++ b/crates/lance-context-master/src/main.rs @@ -71,13 +71,13 @@ async fn main() { let listener = TcpListener::bind(&addr).await.unwrap(); axum::serve(listener, app) - .with_graceful_shutdown(shutdown_signal()) + .with_graceful_shutdown(wait_for_shutdown_signal()) .await .unwrap(); } #[cfg(unix)] -async fn shutdown_signal() { +async fn wait_for_shutdown_signal() { use tokio::signal::unix::{signal as unix_signal, SignalKind}; // Kubernetes and other process managers stop containers with SIGTERM. @@ -96,7 +96,7 @@ async fn shutdown_signal() { } #[cfg(not(unix))] -async fn shutdown_signal() { +async fn wait_for_shutdown_signal() { tokio::signal::ctrl_c() .await .expect("failed to install Ctrl+C handler"); diff --git a/crates/lance-context-server/src/main.rs b/crates/lance-context-server/src/main.rs index 6f7f30e0..5a9862a5 100644 --- a/crates/lance-context-server/src/main.rs +++ b/crates/lance-context-server/src/main.rs @@ -81,7 +81,7 @@ async fn main() { let listener = TcpListener::bind(&addr).await.unwrap(); axum::serve(listener, app) - .with_graceful_shutdown(shutdown_signal()) + .with_graceful_shutdown(wait_for_shutdown_signal()) .await .unwrap(); @@ -91,7 +91,7 @@ async fn main() { } #[cfg(unix)] -async fn shutdown_signal() { +async fn wait_for_shutdown_signal() { use tokio::signal::unix::{signal as unix_signal, SignalKind}; // Kubernetes and other process managers stop containers with SIGTERM. @@ -110,7 +110,7 @@ async fn shutdown_signal() { } #[cfg(not(unix))] -async fn shutdown_signal() { +async fn wait_for_shutdown_signal() { tokio::signal::ctrl_c() .await .expect("failed to install Ctrl+C handler");