Skip to content

test(InProcessTestHost): external-event + durable-timer timeout coverage (relates to #713)#764

Open
YunchuWang wants to merge 3 commits into
mainfrom
yunchuwang-repro-issue-713
Open

test(InProcessTestHost): external-event + durable-timer timeout coverage (relates to #713)#764
YunchuWang wants to merge 3 commits into
mainfrom
yunchuwang-repro-issue-713

Conversation

@YunchuWang

Copy link
Copy Markdown
Member

Summary

Adds InProcessTestHost.Tests coverage for external events (TaskOrchestrationContext.WaitForExternalEvent<T>), including the canonical Task.WhenAny(eventTask, timerTask) "wait for an event with a timeout" pattern. This fills a gap in external-event test coverage and documents the correct durable-timer cancellation semantics.

Relates to #713.

Background — #713 is expected behavior

#713 reports that an orchestration awaiting Task.WhenAny(externalEventTask, timerTask) appears to "hang" after the external event is raised, while the durable timer is still pending.

A verification-only investigation shows the external event is delivered and wins the WhenAny. The orchestration does not complete because a durable timer that was created but never cancelled remains outstanding. This is standard Durable Task Framework behavior, already documented on TaskOrchestrationContext.CreateTimer:

All durable timers created using this method must either expire or be cancelled using the cancellationToken before the orchestrator can complete. If unexpired timers exist when the orchestration completes, it will remain in the "Running" state until the scheduled expiration time.

and on Microsoft Learn (durable-functions-timers): the framework doesn't change an orchestration's status to Completed until all outstanding tasks, including durable timer tasks, are either completed or canceled.

The issue's repro uses a 5-minute timer and never cancels it, so the instance stays Running until the timer would fire (~5 min) — which looks like a hang inside a short test. This is not a lost/dropped event and not an InProcessTestHost-specific defect: the worker forwards the CancellationToken straight into DurableTask.Core (TaskOrchestrationContextWrapper.CreateTimer), the same path all backends use.

What this PR adds

test/InProcessTestHost.Tests/ExternalEventTests.cs with three fast, deterministic tests:

  1. WaitForExternalEvent_IsDelivered — a plain external event is delivered to a waiting orchestration and its payload is returned (fills the missing plain external-event coverage).
  2. WaitForExternalEvent_WithTimeout_EventWins — the canonical pattern: a 5-minute timer under Task.WhenAny; when the event wins, the timer's CancellationTokenSource is cancelled so the orchestration completes promptly (well under the timer) with the event payload.
  3. WaitForExternalEvent_WithTimeout_TimerWins — same shape with a short 2 s timer and no event raised; the timer wins and the orchestration returns "timeout".

Each test uses a 30 s completion CancellationTokenSource purely as a safety guard; all complete in a few seconds.

Notes

Validation

dotnet test test/InProcessTestHost.Tests/InProcessTestHost.Tests.csproj -c Debug -f net10.022 passed, 0 failed (3 new tests + 19 existing).

…overage

Adds InProcessTestHost.Tests coverage for WaitForExternalEvent, including the
canonical Task.WhenAny timeout pattern that cancels the durable timer when the
event wins. Documents that an orchestration does not complete while a durable
timer is still outstanding. Relates to #713.

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds new InProcessTestHost.Tests coverage for external event delivery (TaskOrchestrationContext.WaitForExternalEvent<T>), including the common “external event with durable-timer timeout” Task.WhenAny pattern described in #713, to document correct completion/cancellation behavior in the in-process test host.

Changes:

  • Added a new test suite validating basic external-event delivery.
  • Added timeout-pattern tests covering both “event wins” and “timer wins” branches.
  • Included remarks in the test file that point to the durable-timer cancellation requirement documentation.

Comment thread test/InProcessTestHost.Tests/ExternalEventTests.cs Outdated
Comment thread test/InProcessTestHost.Tests/ExternalEventTests.cs Outdated
Comment thread test/InProcessTestHost.Tests/ExternalEventTests.cs
Comment thread test/InProcessTestHost.Tests/ExternalEventTests.cs
kaibocai
kaibocai previously approved these changes Jul 15, 2026
Use WaitForInstanceStartAsync instead of fixed delays, and cancel the losing
external-event wait in the timeout branch to mirror the SDK's
WaitForExternalEvent(name, timeout) helper. Relates to #713.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 15, 2026 20:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 15, 2026 23:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

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.

InMemoryOrchestrationService: External events not delivered when durable timer is pending in Task.WhenAny

4 participants