1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//! Bounding a single await inside a handler, with the failure reported as a step timeout.
use crateOrkaError;
use Future;
use Duration;
/// Awaits `fut` with a time budget, reporting an overrun as
/// [`OrkaError::StepTimedOut`] rather than an anonymous elapsed error.
///
/// Orka imposes no timeouts of its own: it depends on no runtime, so it has no timer and
/// cannot bound a handler for you. This is the small piece it can offer, collapsing the
/// match-and-map every hand-rolled timeout otherwise repeats, and making sure the failure
/// names the step. That matters because [`Pipeline::run`](crate::Pipeline::run) discards
/// the [`RunOutcome`](crate::RunOutcome) that would otherwise carry the attribution, and a
/// fan-out branch keeps only its typed error.
///
/// The budget bounds **this await only**, not the rest of the handler. Reach for it when a
/// specific call may never return, which is the usual shape: waiting on a remote push, a
/// channel that may go quiet, a socket read.
///
/// ```ignore
/// pipeline.on_root(Step::AwaitArtifact, |ctx| async move {
/// let (rx, budget) = ctx.with_ref(|c| (c.archive_ready_rx.clone(), c.artifact_timeout));
///
/// // Two independent failure modes, so two unwraps: the timeout, then the receive.
/// let msg = timed(Step::AwaitArtifact, budget, rx.recv()).await??;
///
/// ctx.with_mut(|c| c.artifact_id = msg.artifact_id);
/// Ok(PipelineControl::Continue)
/// });
/// ```
///
/// The returned `OrkaError` converts into the pipeline's own error type through the
/// `From<OrkaError>` bound every pipeline error carries, so a single `?` discharges it.
///
/// On expiry `fut` is dropped, abandoning whatever it had in flight. The run itself
/// continues to its exit, so its [`on_finish`](crate::Pipeline::on_finish) ring still runs
/// and its [`resources`](crate::ContextData::resources) bag still releases at the usual
/// point. Only state the future held locally is lost, which is a reason to stash anything
/// needing orderly shutdown (a stream sender, a lock guard) in the resource bag rather
/// than in a local.
pub async