Summary
Introduce a durable_async!() macro that wraps an async block into a DurableFuture, enabling it to be used in select2() and join() alongside other durable futures.
Motivation
In tokio, you can race arbitrary async blocks:
tokio::select! {
res = single_operation() => { ... }
res = async {
let a = step1().await;
let b = step2(a).await;
b
} => { ... }
}
In duroxide, select2() only accepts DurableFuture, so users must create sub-orchestrations to race groups of sequential operations. This is verbose and scatters workflow logic.
Proposed Solution
let (winner, _) = ctx.select2(
ctx.schedule_activity("Fast", input.clone()),
durable_async!(ctx, {
let a = ctx.schedule_activity("Step1", input).into_activity().await?;
let b = ctx.schedule_activity("Step2", a).into_activity().await?;
Ok(b)
}),
).await;
Key Features
- Inline definition: No pre-registration required
- Same instance: Runs in the same orchestration, same history
- Full control flow: Supports
if, for, match, loop, continue, break, early return
- Scoped cancellation: When used in
select2, losing branch activities are cancelled
- Helper functions: Can call async helper functions that use the context
Implementation Overview
- Add
Kind::Task variant to DurableFuture
- Add scope tracking to
CtxInner (scope stack, activity-to-scope mapping)
- Implement
durable_async! macro
- Update
AggregateDurableFuture to cancel loser scope activities
Example Use Cases
- Racing a quick check against a multi-step validation pipeline
- Timeout around a complex provisioning sequence
- Racing two alternative processing paths
Related
- Proposal document:
proposals/durable-async-macro.md
- Activity cancellation uses the same provider mechanism (queue deletion)
Tasks
Summary
Introduce a
durable_async!()macro that wraps an async block into aDurableFuture, enabling it to be used inselect2()andjoin()alongside other durable futures.Motivation
In tokio, you can race arbitrary async blocks:
In duroxide,
select2()only acceptsDurableFuture, so users must create sub-orchestrations to race groups of sequential operations. This is verbose and scatters workflow logic.Proposed Solution
Key Features
if,for,match,loop,continue,break, earlyreturnselect2, losing branch activities are cancelledImplementation Overview
Kind::Taskvariant toDurableFutureCtxInner(scope stack, activity-to-scope mapping)durable_async!macroAggregateDurableFutureto cancel loser scope activitiesExample Use Cases
Related
proposals/durable-async-macro.mdTasks
Kind::Taskvariant andDurableOutput::TaskCtxInnerbegin_scope(),end_scope(),register_activity_in_scope()durable_async!macropoll()forKind::TaskAggregateDurableFuturefor scope cancellationselect2withdurable_async!