Graceful shutdown

Handle graceful shutdown base on different signals.

use salvo::prelude::*;
use std::time::Duration;

#[handler]
async fn hello() -> &'static str {
    "Hello World"
}

async fn before_shutdown(kind: &str) {
    tracing::info!("Received {} signal", kind);
    tracing::info!("Cleaning up...");
    for i in (1..=3).rev() {
        tracing::info!("Finishing in {}...", i);
        tokio::time::sleep(Duration::from_secs(1)).await;
    }
}

#[tokio::main]
async fn main() {
    tracing_subscriber::fmt().init();

    let router = Router::new().get(hello);
    let service = Service::new(router).hoop(Logger::new());

    let acceptor = TcpListener::new("0.0.0.0:5800").bind().await;
    let server = Server::new(acceptor);
    let handle = server.handle();

    // Graceful shutdown the server
    tokio::spawn(async move {
        use tokio::signal::ctrl_c;
        use tokio::signal::unix::{signal, SignalKind};
        let mut sigterm = signal(SignalKind::terminate()).unwrap();
        let mut sigint = signal(SignalKind::interrupt()).unwrap();

        tokio::select! {
            _ = sigterm.recv() => before_shutdown("terminate").await,
            _ = sigint.recv() => before_shutdown("interrupt").await,
            _ = ctrl_c() => before_shutdown("ctrl-c").await
        };
        handle.stop_graceful(None);
    });
    server.serve(service).await;
}
[package]
name = "example-graceful-shutdown"
version = "0.1.0"
edition = "2021"
publish = false


[dependencies]
salvo = { workspace = true, features = ["logging"] }
tokio = { version = "1", features = ["macros", "signal"] }
tracing = "0.1"
tracing-subscriber = "0.3"