Search code examples
rustrust-tokio

Is there a way to avoid the usage of `tokio::select!` macro?


I'm using the below code (from here) to handle graceful shutdown:

use tokio::signal;

pub 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 => {},
    }

    tracing::info!("signal received, starting graceful shutdown...");
}

Is there a way to avoid the usage of tokio::select! macro?


Solution

  • You can use futures's select():

    use tokio::signal;
    
    pub 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::pin!(ctrl_c, terminate);
    
        futures::future::select(ctrl_c, terminate).await;
    
        tracing::info!("signal received, starting graceful shutdown...");
    }