Following on from a recent post about signaling handling in Rust, I found that when running my Rust microservices in containers I wasn’t able to Ctrl-C these despite running in docker’s interactive mode.

Here’s some code which allows you to handle this situation gracefully.

Add this to your Cargo.toml’s dependencies section:

signal-hook = "0.1.7"

And this to your program’s main.rs:

extern crate signal_hook;

pub fn reg_for_sigs() {
    unsafe { signal_hook::register(signal_hook::SIGINT, || on_sigint()) }
        .and_then(|_| {
                debug!("Registered for SIGINT");
                Ok(())
        })
        .or_else(|e| {
            warn!("Failed to register for SIGINT {:?}", e);
            Err(e)
        })
        .ok();
}

fn on_sigint() {
    warn!("SIGINT caught - exiting");
    std::process::exit(128 + signal_hook::SIGINT);
}

Then add a call to reg_for_sigs() in your fn main():

fn main() {
    ...
    reg_for_sigs()
    ...
}

Now when running and you hit Ctrl-C you’ll get output like the following when hitting Ctrl-C, and the process will exit.

[2019-01-05T13:48:01Z WARN  myApp] SIGINT caught - exiting

Note that the reg_for_sigs() method deliberately swallows and logs any error, rather than leaving it for main() to handle. If you want to see the logs, you’ll need to use the log crate.