Rayon: Catching panic from `par_iter()`

could you please point me what I'm doing wrong with catching panic:
This is rayon question - not about handling the particular vector panic in the example but any possible panic, as I am writing a map function which may or may not have panics (something I don't control). But because my map function runs are independent I would like to a) get a callback of which entry panicked, b) keep going through the list. I do not want the application to abort. eventually I would like to send panics up to a error handling service like sentry.

if I have this, I'm getting everything correct( no panic)

let dog: Dog = Dog{name: "Dog", vector: vec![1,2,3,4,5]};
    let cat: Cat = Cat{name: "Cat", vector: vec![1,2,3]};
    let pig: Pig = Pig{name: "Pig", vector: vec![1,2,3,4,5]};
    let mut v: Vec<Box<dyn Animal>> = Vec::new();
    v.push(Box::new(cat));
    v.push(Box::new(dog));
    v.push(Box::new(pig));
    
    let total = v.par_iter().map(|x| {
        println!("{} vector[1] is {:?}", &x.name(), &x.vector()[1]);
        x.vector()[1].clone()
    }).collect::<Vec<(i32)>>();

    let sum: i32 = total.iter().sum();
    println!("sum: {}", sum);

I get sum after par_iter

Cat vector[1] is 2
Dog vector[1] is 2
Pig vector[1] is 2
sum: 6

In case I'm trying to get index which exceeds vector length, than I'm still printing whatever I have incl panic but don't get to the sum:

let total = v.par_iter().map(|x| {
        println!("{} vector[4] is {:?}", &x.name(), &x.vector()[4]);
        x.vector()[4].clone()
    }).collect::<Vec<(i32)>>();

    let sum: i32 = total.iter().sum();
    println!("sum: {}", sum);

the result:

     Running `target/debug/playground`
thread '<unnamed>' panicked at 'index out of bounds: the len is 3 but the index is 4', /rustc/4560ea788cb760f0a34127156c78e2552949f734/src/libcore/slice/mod.rs:2717:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
Standard Output
Dog vector[4] is 5
Pig vector[4] is 5

Tried to implement panic_handler like that - to check what I could do with panic_handler

 let panic_handler = move |err: Box<dyn Any + Send>| {
        println!("hello");
    };
    rayon::ThreadPoolBuilder::new().num_threads(2).panic_handler(panic_handler).build_global().unwrap();

but obviously it's not working and not even used:

warning: unused variable: `err`
  --> src/main.rs:52:31
   |
52 |     let panic_handler = move |err: Box<dyn Any + Send>| {
   |                               ^^^ help: consider prefixing with an underscore: `_err`

the playground
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c79f61b10331c930be9c5b4e4bce103f

PS: it's not the problem of indices of Vector which is obvious, It's the question about catching panic from par_iter if I don't know would it panic or not, and my goal is to prevent rayon default behavior which aborts the process.

thank you

1 Like

You need to use ::std::panic::catch_unwind():

1 Like

amazing, thank you!
I've read about ::std::panic::catch_unwind() in rayon panic_handler but couldn't realize how to implement it.

Is there anyway that Rayon can stop propagating the panic? How does “panic_handler” on the Rayon global configuration affect things?

My main problem with the solution code is that it wraps the whole block in a complex exception callback. It’d be nice if Rayon could do this natively and all the code is chained in to Rayon.

Edit: looks like panic_handler is ONLY for spawned tasks. That’s unfortunate (and a little confusing).

1 Like