microsoft / microsoft/duroxide

Forward unmatched external events to running sub-orchestrations

Open
#21 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
217
Forks
61
Avg merge
2d 22h
Merged PRs (30d)
3

Description

Forward unmatched external events to running sub-orchestrations

Problem

Client::raise_event(instance_id, name, data) only delivers the event to the orchestration whose ID is instance_id. If a schedule_wait(name) is awaiting inside a sub-orchestration spawned by schedule_sub_orchestration (e.g. parallel branches via join / select), an event raised on the parent never reaches those waiters.

From a caller's perspective the sub-orchestration is an implementation detail — the auto-generated IDs ({parent}::sub::{event_id}) aren't part of the public contract and aren't known to external signalers, so there's no practical way for a client to target the child directly.

Repro sketch
// orchestration
ctx.schedule_sub_orchestration("child", input).await?; // child awaits schedule_wait("approve")

// caller
client.raise_event(parent_id, "approve", data).await?; // never observed by child
Workarounds today

Callers can walk get_instance_tree(parent) and raise_event on each running descendant, but this has races:

  • Descendant may be Pending (not yet Running) when enumerated and gets skipped.
  • Event may arrive before the sub-orchestration is even scheduled; it then lands on the parent's pending queue with no consumer.
  • Broadcasts to every descendant regardless of whether they actually subscribe to that event name.
Proposed direction

Some options worth considering — happy to discuss which fits the model best:

  1. Inheritance on miss: an unmatched raise_event on a parent is buffered and offered to sub-orchestrations as they reach a matching schedule_wait. Symmetric to how schedule_wait already buffers events that arrive before the wait is registered.
  2. Explicit broadcast API: Client::raise_event_tree(root, name, data) (or a flag on raise_event) that durably fans the event out to the root and all current/future descendants until they complete.
  3. Subscription registration: sub-orchestrations register a "forward name from parent" subscription when they call schedule_wait, and the runtime routes parent events accordingly.

Option 1 is the most ergonomic for callers since they don't need to know the topology. Option 2 is the smallest API change but pushes timing responsibility back to the client.

Why this matters

Any orchestration pattern that fans out work into sub-orchestrations and then expects a human-in-the-loop or external system to signal one of those branches is currently unreachable without out-of-band coordination. Approval flows inside parallel branches, cancel-style signals targeting a specific competitor in a race, etc.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing Client::raise_event, schedule_wait, and schedule_sub_orchestration, then review how get_instance_tree exposes running descendants. Compare the proposed inheritance, broadcast, and subscription behaviors, including events raised before a child is scheduled. Done requires a decided routing model and verified behavior for the parent/child approval scenario and its timing races.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend, distributed-systems
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.