Skip to content

[Async stack 2/6] asyncio composition - #359

Closed
andystaples wants to merge 1 commit into
andystaples-async-stack-1-coroutine-dispatchfrom
andystaples-async-stack-2-asyncio-composition-46b
Closed

andystaples wants to merge 1 commit into
andystaples-async-stack-1-coroutine-dispatchfrom
andystaples-async-stack-2-asyncio-composition-46b

Conversation

@andystaples

Copy link
Copy Markdown
Contributor

Warning

Do not merge this PR, or any other PR in this stack, on its own. The stack exists only to make review easier. Once every PR in the stack is approved, the whole stack will be squash-merged together.

Part of the reviewability stack split from #293. This PR is based on the coroutine-dispatch layer (#357).

Scope

This PR extends the deterministic orchestration event loop in durabletask/internal/asyncio_loop.py. It adds support for standard asyncio composition primitives inside async orchestrators:

  • Tasks: create_task returns a _DurableAsyncTask that is retired when it completes, so finished tasks and their payloads are released.
  • Deterministic ready queue: call_soon keeps FIFO order. While a task is being cancelled, callbacks scheduled during that cancellation are ordered deterministically. This keeps TaskGroup cancellation, and the durable actions it produces, stable across replays.
  • Durable timers: call_later and call_at are backed by durable timers through _DurableTimerHandle.
    • Non-finite delays are rejected.
    • Past deadlines go straight to the ready queue.
    • Deadlines are rounded up to the timer resolution so a callback never fires early.
    • Cancelling a handle also cancels its durable timer.
    • Handles are compared by identity, so identical callbacks scheduled at the same time stay independent.
  • As a result, asyncio.sleep, asyncio.wait_for, asyncio.timeout, asyncio.gather, and asyncio.TaskGroup work inside async orchestrators.

Review focus

  • Ordering rules for call_soon versus cancellation callbacks, and the durable actions they produce.
  • Deadline rounding, and how cancelling a timer handle interacts with its durable timer.
  • Whether local task cancellation stops a waiter without cancelling durable work that other waiters still share.

Deferred to later layers

  • Dispatch teardown: closing the loop, async-generator finalization, the cleanup-error policy, and guards for unsupported I/O and executors.
  • Cold context: the AsyncOrchestrationContext API surface.
  • Azure Functions integration and release notes.

The tests in this layer use the existing OrchestrationContext APIs. Later layers move them to the async context.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@andystaples

Copy link
Copy Markdown
Contributor Author

Superseded by #358, which is the canonical layer 2 of this stack.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant