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

Spawning and Joining — run_fork and fiber_all

The current API uses run_fork to spawn effects and FiberHandle methods to join, inspect, or interrupt them.

run_fork: Spawn One Fiber

use effectful::{ThreadSleepRuntime, run_fork};

let runtime = ThreadSleepRuntime;
let handle = run_fork(&runtime, || (compute_expensive_result(), env));

let local_result = local_computation();
let remote_result = handle.join().await?;

(local_result, remote_result)

The factory returns (effect, env) so the worker owns both the one-shot effect and its environment.

await_exit vs join

let exit: Exit<A, E> = run_async(handle.await_exit(), ()).await?;
let result: Result<A, Cause<E>> = handle.join().await;

Use await_exit when you want the exact Exit; use join for a Result with Cause<E> on failure.

fiber_all

fiber_all joins already-created handles.

use effectful::{fiber_all, run_async};

let handles = user_ids
    .into_iter()
    .map(|id| run_fork(&runtime, move || (fetch_user(id), ())))
    .collect::<Vec<_>>();

let users: Vec<User> = run_async(fiber_all(handles), ()).await?;

If any handle fails, fiber_all returns the first Cause<E> it observes.

Racing

There is no fiber_race or fiber_any free function in the current API. FiberHandle::or_else races two handles and completes with whichever handle resolves first.

let primary = run_fork(&runtime, || (fetch_from_primary(), ()));
let backup = run_fork(&runtime, || (fetch_from_backup(), ()));

let raced = primary.or_else(backup);
let data = raced.join().await?;

The slower fiber is not automatically cancelled by or_else; keep its handle if you need to interrupt it.

Error Behavior

OperationFailure shape
handle.join().awaitResult<A, Cause<E>>
handle.await_exit()Exit<A, E> inside an infallible effect
fiber_all(handles)Effect<Vec<A>, Cause<E>, ()>
handle.or_else(other)First handle completion wins