5

My application is based around a library (Library-A) that uses actix and actix-web. I am adding a second library (Library-B) that runs an http server, also using actix-web. I use a separate thread and actix::system for this. On a SIGINT, only the Library-B actix systems closes, leaving the Library-A running. No subsequent SIGINT closes the running actix system.

What is the correct way to gracefully close down two running actix systems?

The code for Library-B, to start a new actix system and run an http server:

thread::spawn(move || {
    let sys = actix::System::new("monitor");
    server::new(|| App::new()
        .route("/metrics", http::Method::GET, endpoint))
        .bind(format!("0.0.0.0:{}", port))
        .unwrap()
        .start();
    sys.run();
    println!("Closing monitor actix system");
    // --- SIGINT gets me here... how do I shut down gracefully?
});

Is it correct for me to start a new system for an independent library? How do I shut down gracefully?

hellow
  • 12,430
  • 7
  • 56
  • 79
zakum1
  • 895
  • 6
  • 20

1 Answers1

5

You can catch Ctrl+C signal with the usage of ctrlc crate.

The usage in main thread can be found in Rust-Lang-Nursery

Since you create your threads from your main thread and after you catched the signal in your main thread, Then you can gracefully shutdown other threads via watching shared boolean value in these threads.

As an addition there is a stop functionality which is specific to Actix.

You can also use chan-signal crate and write your custom implementation like answered here

To create your own shutdown logic

Check a shared Arc atomic boolean value in all the threads and stop the execution when this variable is changed in the main thread. Since you catch the ctrl-c signal on main thread it can notify other actor threads like following:

use ctrlc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;

fn main() {
    let running = Arc::new(AtomicBool::new(true));
    let running2 = running.clone();
    let r = running.clone();

    let thandle = thread::spawn(move || {
        while running2.load(Ordering::Relaxed) {
            //Do your logic here
        }
        println!("Thread1 stopped.")
    });

    let thandle2 = thread::spawn(move || {
        while running.load(Ordering::Relaxed) {
            //Do your different logic here
        }
        println!("Thread2 stopped.")
    });

    ctrlc::set_handler(move || {
        r.store(false, Ordering::Relaxed);
    })
    .expect("Error setting Ctrl-C handler");

    println!("Waiting for Ctrl-C...");
    let _ = thandle.join();
    let _ = thandle2.join();
}
Akiner Alkan
  • 6,145
  • 3
  • 32
  • 68