0

I am buffering data which is flushed at intervals. There are cases where the application could (would) exit and that data should be flushed immediately regardless of the interval (i.e. exit(0/1/...) in some other module etc.)

I have a combination of implementing Drop and handling sending pending data when drop is called. (trivial case where the objects are torn down elegantly)

impl Drop for AnalyticsSendQueue {
    fn drop(&mut self) {
        self.flush();
    }
}

I've added a signal_hook to the best of my understanding:

if let Ok(mut s) = signal_hook::iterator::Signals::new(signal_hook::consts::TERM_SIGNALS) {
    let bulk = Arc::clone(&self.bulk);
    std::thread::spawn(move || {
        for _ in s.forever() {
            info!("got a signal");
            let _ = bulk.lock().unwrap().send();
            std::process::exit(1);
        }
    });
} else {
    info!("error with signals");
}

Per my tests, this code isn't invoked when another module does exit(code)

For instance, I created a trivial background thread which will sleep for several seconds and then call exit. The handlers aren't called (they are registered though, verified through logging and breakpoints):

std::thread::spawn(|| {
    std::thread::sleep(Duration::from_secs(10));
    std::process::exit(0); // handlers aren't invoked
});

Is there a way to resolve this?

EDIT!!!! My main concern is if "exit" gets called from some other module which I don't control

Avba
  • 14,822
  • 20
  • 92
  • 192
  • 3
    "Per my tests this code isn't invoked when the user performs kill -9" - and it won't be, whatever you do. `kill -9` terminates the program immediately, without any chance for it to react. – Cerberus May 20 '21 at 14:50
  • 4
    Make your program resistant to removing the power plug from the computer. Then you will be equally resistant to `kill -9` – Shepmaster May 20 '21 at 15:16
  • @Cerberus that's the intention of `SIGKILL`, it doesn't play around, it just kills the process instantly, there's alternative signal `SIGTERM` that is softer and program is supposed to terminate on its own, if it ignores it, it continues to run as if nothing happened. Most systems that want to kill process politely usually send `SIGTERM`, wait a bit and if the process isn't out yet on its own, it assumes that its not cooperating and `SIGKILL`'s it. There's no sane way to avoid termination from `SIGKILL`. In fact, it is recommended to never use `kill -9` in the first place, but internet... – Kaihaku May 20 '21 at 15:17
  • @Shepmaster maybe they should also make the program resistant to OS bugs, hardware bugs that may or may not happen as the hardware ages, solar radiation and so on...? If someone `kill -9`'s your program they don't care about consequences, and neither does any programmer writing the code. It is simply out of scope, just as much as you pulling the plug from your computer. All systems that matter, first of all are resistant to power outages in the first place, and that's the proper way to solve the problem - to not let power go out, not assume that power may go out at any time. – Kaihaku May 20 '21 at 15:20
  • relevant: https://www.youtube.com/watch?v=IuGjtlsKo4s – trent May 20 '21 at 15:22
  • never mind the kill -9 case. what about the "simpler" "exit called from somewhere within the application". How do you hook to that? I could argue that there is a panic handler callback. is there a "exit handle callback" – Avba May 20 '21 at 15:25
  • This now looks like a very different question. If you don't find the answer by yourself, I suggest you ask a new question with a SRE based on this new "exit" problem. – Denys Séguret May 20 '21 at 15:33
  • 1
    All `std::process::exit` does (on Linux, at least) is call libc's `exit`, so presumably you could call `libc::atexit` and pass it a function pointer, but I'm not aware of anything in `std` – trent May 20 '21 at 15:35
  • Even if you used something like `atexit`, then uncontrolled code in your process could shell out to the `kill` command line program and kill itself. Even easier, they could call `std::process::abort()`. You _can't_ prevent someone dedicated to stopping the program. Thus my point about pulling the power plug - once you are resilient against unexpected exits, then everything beyond that is just improving performance. – Shepmaster May 20 '21 at 17:29

0 Answers0