Search code examples
rustrust-tokio

Use tokio::select! to wait for multiple signals fails with a temporary value dropped while borrowed error


In a tokio project I want to wait form both SIGTERM and SIGINT

To just wait for one of the signal works fine:

     tracing::debug!("Waiting for the end of the world");
     signal(SignalKind::terminate())?.recv().await;

But when I try to use tokio::select! from this answer in users.rustlang.org

use tokio::signal::unix::{signal, SignalKind};
tokio::select! {
    _ = signal(SignalKind::interrupt())?.recv() => println!("SIGINT"),
    _ = signal(SignalKind::terminate())?.recv() => println!("SIGTERM"),
}
println!("terminating the process...");

I get an error about a temporary variable being freed while still in use.

error[E0716]: temporary value dropped while borrowed
   --> src/main.rs:495:13
    |
494 |       let ans = tokio::select! {
    |  _______________-
495 | |         _ = signal(SignalKind::interrupt())?.recv() => println!("SIGINT"),
    | |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
496 | |         _ = signal(SignalKind::terminate())?.recv() => println!("SIGTERM"),
497 | |     };
    | |     -
    | |     |
    | |_____temporary value is freed at the end of this statement
    |       borrow might be used here, when `futures` is dropped and runs the destructor for type `(impl futures_util::Future<Output = std::option::Option<()>>, impl futures_util::Future<Output = std::option::Option<()>>)`

Is this still the way to do this?

This question is similar but address a different aspect Programmatically create and listen for multiple signals and a ticking interval with tokio


Solution

  • The example refereed in the question has a small bug. If the Result<Signal> from signal is handled outside of the select! macro there is no temporary variable to outlive its borrowed scope.

        println!("Waiting for the end of the world");
        
        let mut sigterm = signal(SignalKind::terminate())?;
        let mut sigint = signal(SignalKind::interrupt())?;
    
        tokio::select! {
            _ = sigterm.recv() => {println!("SIGTERM Shuting down");},
            _ = sigint.recv() => {println!("SIGINT Shuting down");},
        };