Skip to content

Honor explicit abandonment in the in-process test host - #814

Open
wangbill (YunchuWang) wants to merge 2 commits into
mainfrom
yunchuwang-test-host-explicit-abandonment
Open

wangbill (YunchuWang) wants to merge 2 commits into
mainfrom
yunchuwang-test-host-explicit-abandonment

Conversation

@YunchuWang

Copy link
Copy Markdown
Member

Summary

What changed?

  • Honor explicit activity and orchestration abandonment in the in-process test host. Cancel the abandoned delivery's pending execution so the existing dispatcher releases and requeues it.
  • Issue a fresh completion token for every delivery. Coordinate completion, partial orchestration responses, abandonment, and failure cleanup by that token so duplicate or stale requests cannot settle or erase a replacement.
  • Preserve successful results and worker history streaming. Abandonment discards the episode's partial actions and releases only its replay snapshot; captured readers and replacement snapshots remain valid.

Why is this change needed?

The worker already sends explicit abandonment requests when it rejects or cannot process work. The test-host receiver acknowledged those requests without settling the pending execution, leaving the dispatcher waiting indefinitely instead of retrying the work.

Issues / work items

  • Resolves: N/A
  • Related: #467 added worker-side abandonment on processing failure; this PR fixes only the in-process receiver.

Project checklist

  • Release notes are not required for the next release
    • Otherwise: Notes added to release_notes.md
  • Backport is not required
    • Otherwise: Backport tracked by issue/PR #issue_or_pr
  • All required tests have been added/updated (unit tests, E2E tests)
  • Breaking change?
    • If yes:
      • Impact: Intentional request-acceptance and abandonment-timing behavior change for direct gRPC consumers; SDK signatures, wire fields, persisted data, and current SDK workers are unchanged.
      • Migration guidance: Echo the delivered completionToken in completion, partial-response, and abandonment requests; use a replacement delivery's new token rather than an old token.

AI-assisted code disclosure (required)

Was an AI tool used? (select one)

  • No
  • Yes, AI helped write parts of this PR (e.g., GitHub Copilot)
  • Yes, an AI agent generated most of this PR

If AI was used:

  • Tool(s): GitHub Copilot
  • AI-assisted areas/files: Test-host receiver, abandonment regression/integration tests, token-aware snapshot tests, and the test-host README.
  • What you changed after AI output: The agent refined the loopback observer to count successful writes rather than attempted sends and added competing-settlement and captured-reader coverage. No separate human-authored revisions are claimed.

AI verification (required if AI was used):

  • I understand the code and can explain it
  • I verified referenced APIs/types exist and are correct
  • I reviewed edge cases/failure paths (timeouts, retries, cancellation, exceptions)
  • I reviewed concurrency/async behavior
  • I checked for unintended breaking or behavior changes

Testing

Automated tests

  • Result: Passed locally. Before the receiver change, eight expected-behavior direct-server cases failed and both localhost redelivery cases timed out. After the change:
Command Result
dotnet test test\InProcessTestHost.Tests\InProcessTestHost.Tests.csproj --configuration Release --no-build --no-restore --filter "FullyQualifiedName~WorkItemAbandonment|FullyQualifiedName~WorkerHistorySnapshotTests" --verbosity quiet Passed: 27/27; also passed three consecutive stability runs.
dotnet test test\InProcessTestHost.Tests\InProcessTestHost.Tests.csproj --configuration Release --no-restore --verbosity quiet Passed: 79/79 in the owning suite.
dotnet build src\InProcessTestHost\InProcessTestHost.csproj --configuration Release --no-restore --verbosity quiet Passed for net6.0, net8.0, and net10.0; zero errors.
dotnet pack src\InProcessTestHost\InProcessTestHost.csproj --configuration Release --no-build --no-restore --verbosity quiet Passed for the owning package.
git diff --check origin/main...HEAD Passed.

The build has existing analyzer warnings. Hosted CI has not run; full-solution, emulator, and real Azure suites were not run for this test-host-only change.

Manual validation (only if runtime/behavior changed)

  • Environment (OS, .NET version, components): Windows; .NET SDK 10.0.401 / runtime 10.0.12; ephemeral localhost Kestrel/gRPC, the in-memory orchestration service, and a compatible SDK worker.
  • Steps + observed results: No separate human manual validation was performed. The automated behavior scenarios:
    1. A protocol-level worker receives an orchestration or activity delivery, stops fetching, and explicitly abandons that delivery using its token.
    2. A compatible version-2 SDK worker completes the redelivery and an unrelated instance. Both scenarios assert exactly one explicit abandonment, exactly two successful deliveries of the rejected work, distinct nonempty tokens, and completed instance outputs.
    3. Direct-server tests cover competing completion/abandonment, stale and duplicate tokens, invalid identity, delayed old send cleanup, partial responses, snapshot release, captured readers, and completion after stream disconnection.
  • Evidence (optional): Bounded local console/TRX RED and GREEN evidence retained with the prepared PR packet.

Notes for reviewers

Breaking Change

Type: behavioral (direct gRPC request acceptance and explicit-abandonment timing).

Impact: SDK signatures, protobuf wire fields, persisted JSON, and orchestrator replay code are unchanged, and current SDK workers already echo the delivered token. Direct gRPC callers that previously completed work using only instance/task identity must now supply a nonempty delivery token. Missing tokens return InvalidArgument; unknown or already settled tokens return NotFound; mismatched completion identity returns InvalidArgument without consuming the active delivery. A successful explicit abandonment now settles that execution and enables dispatcher retry instead of leaving it pending after acknowledgment.

Migration: Echo the WorkItem.completionToken in activity completion, orchestrator partial/final completion, and abandonment requests. A replacement delivery has a new token; do not reuse a settled delivery's token to target the replacement.

  • This is explicit abandonment only. Closing GetWorkItems does not cancel or redispatch already delivered work. No activity timeout, heartbeat/lease policy, production DTS change, worker-policy change, entity support, or hub-lifecycle change is included.
  • Release-note, backport, human verification, and hosted CI decisions remain unchecked for maintainer review.

Assign a fresh completion token to each activity and orchestration delivery. Coordinate completion, partial responses, explicit abandonment, and cleanup using that delivery's ownership so stale requests cannot settle a replacement. Cancel explicitly abandoned executions so the existing dispatcher requeues them, while preserving the stream-disconnect policy.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4a00a0f1-0b30-44f9-83a2-27dad922625f
Copilot AI balanced review requested due to automatic review settings October 9, 2026 14:47
Comment on lines +643 to +655
if (request.FailureDetails == null)
{
resultEvent = new TaskCompletedEvent(-1, request.TaskId, request.Result);
}
else
{
resultEvent = new TaskFailedEvent(
eventId: -1,
taskScheduledId: request.TaskId,
reason: null,
details: null,
failureDetails: ProtobufUtils.GetFailureDetails(request.FailureDetails));
}
using CancellationTokenSource connectionCancellation = new();
using AsyncServerStreamingCall<P.WorkItem> rejectingWorker = client.GetWorkItems(
new(), cancellationToken: connectionCancellation.Token);
IHost? compatibleWorker = null;
sealed class ServerSession : IAsyncDisposable
{
readonly CancellationTokenSource stopping = new();
readonly CancellationTokenSource connectionCancellation = new();

sealed class ServerSession : IAsyncDisposable
{
readonly CancellationTokenSource stopping = new();

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.

🟡 Changes recommended

A delayed stream-write failure can override an already-acknowledged completion and incorrectly requeue completed work.

1 open finding
What changed in this PR

Adds receiver-side support for the explicit abandonment introduced by #467, using per-delivery completion tokens to prevent stale settlements.

Changes:

  • Cancels and requeues explicitly abandoned work.
  • Coordinates completion, partial responses, snapshots, and abandonment by delivery token.
  • Adds direct-server and localhost integration coverage plus documentation.
File Description
src/​InProcessTestHost/​Sidecar/​Grpc/​TaskHubGrpcServer.cs Implements token-based delivery ownership and abandonment.
src/​InProcessTestHost/​README.md Documents abandonment semantics and migration requirements.
test/​InProcessTestHost.Tests/​WorkItemAbandonmentTests.cs Tests settlement, concurrency, and cleanup behavior.
test/​InProcessTestHost.Tests/​WorkItemAbandonmentIntegrationTests.cs Tests end-to-end redelivery through gRPC.
test/​InProcessTestHost.Tests/​WorkerHistorySnapshotTests.cs Updates snapshot tests for completion tokens.

🧠 Review effort: Balanced


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/InProcessTestHost/Sidecar/Grpc/TaskHubGrpcServer.cs
Let send-failure cleanup claim delivery ownership under the same lock as completion and abandonment. When a successful completion already won, return its accepted result for both activity and orchestrator execution instead of requeueing it.

Add deterministic completion-before-send-failure coverage for both dispatch paths and document the settlement policy.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5777cc4b-513e-47b7-a159-75ad5e8a7298
Copilot AI balanced review requested due to automatic review settings October 9, 2026 21:11

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.

🟢 Approval recommended

The behavioral breaking change is documented with migration guidance and comprehensively tested.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

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.

3 participants