//! Run with //! //! ```not_rust //! cargo run -p example-graceful-shutdown //! kill or ctrl-c //! ``` use std::time::Duration; use axum::{routing::get, Router}; use tokio::net::TcpListener; use tokio::signal; use tokio::time::sleep; use tower_http::timeout::TimeoutLayer; use tower_http::trace::TraceLayer; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; #[tokio::main] async fn main() { // Enable tracing. tracing_subscriber::registry() .with( tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| { format!( "{}=debug,tower_http=debug,axum=trace", env!("CARGO_CRATE_NAME") ) .into() }), ) .with(tracing_subscriber::fmt::layer().without_time()) .init(); // Create a regular axum app. let app = Router::new() .route("/slow", get(|| sleep(Duration::from_secs(5)))) .route("/forever", get(std::future::pending::<()>)) .layer(( TraceLayer::new_for_http(), // Graceful shutdown will wait for outstanding requests to complete. Add a timeout so // requests don't hang forever. TimeoutLayer::new(Duration::from_secs(10)), )); // Create a `TcpListener` using tokio. let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap(); // Run the server with graceful shutdown axum::serve(listener, app) .with_graceful_shutdown(shutdown_signal()) .await .unwrap(); } async fn shutdown_signal() { let ctrl_c = async { signal::ctrl_c() .await .expect("failed to install Ctrl+C handler"); }; #[cfg(unix)] let terminate = async { signal::unix::signal(signal::unix::SignalKind::terminate()) .expect("failed to install signal handler") .recv() .await; }; #[cfg(not(unix))] let terminate = std::future::pending::<()>(); tokio::select! { _ = ctrl_c => {}, _ = terminate => {}, } }