Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Operations Reference

Sequential operations

then

Dispatches a single task with the previous step’s result.

#![allow(unused)]
fn main() {
.first::<TaskA>()
.then::<TaskB>()    // TaskB::Input must equal TaskA::Output
}

tap

Dispatches a fire-and-forget side task without affecting the pipeline result. The side task receives the current result but runs independently. The pipeline continues with the original result unchanged.

#![allow(unused)]
fn main() {
.first::<ProcessData>()
.tap::<AuditLog>()      // AuditLog runs in background
.then::<SaveResult>()   // receives ProcessData's output, not AuditLog's
}

Works in both sequential and fan-out contexts.

Fan-out operations

fan_out

Splits an iterable into parallel children. The previous step must return something that implements IntoIterator.

#![allow(unused)]
fn main() {
.first::<FindItems>()   // () -> Vec<Item>
.fan_out()               // dispatches one child per Item
.then::<ProcessItem>()   // Item -> Result
}

fan_out_chunked

Like fan_out, but groups items into fixed-size batches before dispatching. Each per-item task receives Vec<Item> instead of Item. Batch size is a runtime parameter.

#![allow(unused)]
fn main() {
.first::<FindUrls>()              // () -> Vec<Url>
.fan_out_chunked::<Url>(100)      // dispatches one child per chunk of 100
.then::<ProcessUrlBatch>()        // Vec<Url> -> BatchResult
.collect()                        // Vec<BatchResult>
}

flat_map

Like then inside a fan-out, but the task returns an iterable that spawns additional children within the same barrier. Enables nested parallelism without intermediate collect/flatten cycles.

#![allow(unused)]
fn main() {
.fan_out()
.flat_map::<ExpandItem>()  // Item -> Vec<SubItem>, each SubItem becomes a child
.then::<ProcessSubItem>()  // SubItem -> Result
.collect()                 // gathers ALL leaf results
}

Terminator operations

Terminators close a fan-out context and return to sequential mode.

collect

Gathers all parallel results into a Vec.

#![allow(unused)]
fn main() {
.fan_out()
.then::<Process>()
.collect()          // Sequential<B, In, Vec<ProcessOutput>>
}

wait

Waits for all children to complete but discards their results. The next step receives a null payload.

#![allow(unused)]
fn main() {
.fan_out()
.then::<Process>()
.wait()             // Sequential<B, In, ()>
.then::<Notify>()   // Notify::Input = ()
}

race

Resolves on the first child to complete. All other children’s results are discarded. The winning child’s result is forwarded.

#![allow(unused)]
fn main() {
.fan_out()
.then::<TryResolver>()
.race()             // Sequential<B, In, ResolverOutput>
.then::<UseResult>()
}

reduce

Gathers results, then sequentially folds them with a reducer task. The reducer receives (Accumulator, Item) and returns Accumulator.

#![allow(unused)]
fn main() {
.fan_out()
.then::<Process>()
.reduce::<Fold, u64>(0)  // Sequential<B, In, u64>
}

sink

Fire-and-forget terminal. Dispatches a task without waiting for its result. The pipeline resolves immediately with an empty payload.

#![allow(unused)]
fn main() {
.first::<Prepare>()
.sink::<Notify>()    // Terminated<B, In>
}

Can also terminate a fan-out, dispatching the sink task for each child independently.

Modifiers

retry

Sets a retry policy on the preceding then step. When the task returns an error, the worker re-dispatches it with the original input up to max_retries times before aborting the pipeline.

#![allow(unused)]
fn main() {
.first::<FetchData>()
.then::<ProcessData>().retry(3)   // retry up to 3 times on failure
.then::<SaveResult>()
}

Works in both sequential and fan-out contexts.