Course contentsShow
← Rust
Lesson 887 of 1,9107. Error Handling PatternsFree lesson

Error Propagation in Parallel Pipelines

Coordinating error states across multiple parallel Rayon-based tasks.

In this lesson, you will learn how to orchestrate error handling when processing data across multiple threads using Rayon, ensuring that a single failure doesn't leave your pipeline in an inconsistent state.

When you use Rayon to parallelize a collection (e.g., via par_iter), you often run into a dilemma: the iterator expects a successful result, but your operations might return Result<T, E>. If you simply collect these results, you end up with a Vec<Result<T, E>>. If you want the entire pipeline to "short-circuit" upon the first error—mirroring how ? works in sequential code—you need a strategy to coordinate these outcomes.

The idiomatic way to achieve this is by using collect() into a Result. Because Result implements FromIterator, if your collection contains a single Err, the entire collect call will return that Err immediately.

Consider this pipeline:

use rayon::prelude::*;

fn process_data(items: Vec<i32>) -> Result<Vec<i32>, String> {
    items.par_iter()
        .map(|&i| {
            if i < 0 {
                Err(format!("Negative value found: {}", i))
            } else {
                Ok(i * 2)
            }
        })
        .collect() // If any item is Err, this returns Err immediately
}

Coordination Challenges

While collect() is convenient, it can be wasteful. In a massive parallel pipeline, one error doesn't stop the other threads from continuing their work. If your task is expensive, you might prefer to stop processing as soon as an error is detected. To do this, you can use find_map or try_for_each. These methods allow you to inspect the results and short-circuit the processing across all threads the moment an Err is encountered, effectively synchronizing the error state across your parallel workers.

When designing these pipelines, always define a clear strategy: do you want to collect all errors for a report (the "collect" approach), or do you want to halt the system immediately (the "try_for_each" approach)? Mixing these patterns without a plan is how race conditions in state recovery begin.

Key Takeaway: Leverage the FromIterator implementation for Result to propagate errors across parallel collections, or use short-circuiting methods like try_for_each to stop execution across all threads as soon as a failure occurs.