Skip to content

Feature: durable_async!() macro for inline task scopes #53

Description

@affandar

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

  1. Add Kind::Task variant to DurableFuture
  2. Add scope tracking to CtxInner (scope stack, activity-to-scope mapping)
  3. Implement durable_async! macro
  4. 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

  • Add Kind::Task variant and DurableOutput::Task
  • Implement scope tracking in CtxInner
  • Implement begin_scope(), end_scope(), register_activity_in_scope()
  • Implement durable_async! macro
  • Implement poll() for Kind::Task
  • Update AggregateDurableFuture for scope cancellation
  • Add unit tests for scope tracking
  • Add integration tests for select2 with durable_async!
  • Add cancellation tests
  • Add replay determinism tests
  • Update documentation

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions