use std::time::Duration; use axum::{routing, Router}; use tokio::{ net::TcpListener, signal::{self, unix::SignalKind}, task::JoinSet, }; use tower_http::{timeout::TimeoutLayer, trace::TraceLayer}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), std::io::Error> { tracing_subscriber::registry() .with(tracing_subscriber::EnvFilter::from_env("LOG_LEVEL")) .with(tracing_subscriber::fmt::layer().json()) .init(); let app = Router::new() .route("/", routing::get(|| async { "Hello world!" })) .layer(( TraceLayer::new_for_http(), TimeoutLayer::new(Duration::from_secs(10)), )); let listener = TcpListener::bind("0.0.0.0:8080").await.unwrap(); axum::serve(listener, app) .with_graceful_shutdown(shutdown_signal()) .await } const SIGNALS: &'static [(i32, &'static str)] = &[ (libc::SIGTERM, "SIGTERM"), (libc::SIGQUIT, "SIGQUIT"), (libc::SIGINT, "SIGINT"), ]; async fn shutdown_signal() { let term_signals = [ SignalKind::terminate(), SignalKind::quit(), SignalKind::interrupt(), ]; let mut futures = JoinSet::new(); for term_signal in term_signals { futures.spawn(async move { signal::unix::signal(term_signal) .expect("failed to install signal handler") .recv() .await; term_signal.as_raw_value() }); } let kind = futures.join_next().await; if let Some(Ok(kind)) = kind { let name = SIGNALS.iter().find(|e| e.0 == kind).unwrap().1; tracing::info!("{} received, shutting down gracefully", name); } }