xand_utils/
threadutils.rs

1use std::{thread::JoinHandle, time::Duration};
2
3/// Use to spawn a thread that will be restarted automatically (after a one second delay) if it
4/// panics. Primarily useful for running an infinite-lifetime job (like a webserver) in another
5/// thread. If the passed function exits cleanly, it is not restarted.
6pub fn spawn_immortal<F, T>(f: F) -> JoinHandle<T>
7where
8    F: FnOnce() -> T + Send + Clone + 'static,
9    T: Send + 'static,
10{
11    std::thread::spawn(move || loop {
12        let handle = std::thread::spawn(f.clone());
13        match handle.join() {
14            Err(_) => (),
15            Ok(h) => {
16                return h;
17            }
18        }
19        std::thread::sleep(Duration::from_secs(1));
20    })
21}
22
23#[cfg(test)]
24mod test {
25    use super::*;
26    use std::sync::atomic::{AtomicU8, Ordering};
27
28    static COUNTER: AtomicU8 = AtomicU8::new(0);
29
30    #[test]
31    fn test_can_restart() {
32        // If you come here confused from test output, yes, this test intentionally spews panics.
33        let jh = spawn_immortal(|| {
34            let v = COUNTER.fetch_add(1, Ordering::SeqCst);
35            if v < 2 {
36                panic!("Ahhhh!");
37            }
38        });
39        jh.join().unwrap();
40    }
41}