From 134a1663a4e538c25360fe3a20b21f77d8fc8e00 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 22:10:59 +0000 Subject: [PATCH 1/3] Initial plan From 498508e9d5ae4cd7dcc99bfca50f062674360ac6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 22:34:10 +0000 Subject: [PATCH 2/3] Fix race condition in WaitForInstanceAsync causing RestartAsync_EndToEnd test to fail The original code had a TOCTOU race condition where a completion notification could be missed if the orchestration completed between checking completion status and adding the waiter. The fix reorders the operations to add the waiter first, then check for completion. Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com> --- .../Sidecar/InMemoryOrchestrationService.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/InProcessTestHost/Sidecar/InMemoryOrchestrationService.cs b/src/InProcessTestHost/Sidecar/InMemoryOrchestrationService.cs index eb8fd042..6bb696d6 100644 --- a/src/InProcessTestHost/Sidecar/InMemoryOrchestrationService.cs +++ b/src/InProcessTestHost/Sidecar/InMemoryOrchestrationService.cs @@ -739,6 +739,12 @@ public void ReleaseLock(string instanceId) public Task WaitForInstanceAsync(string instanceId, CancellationToken cancellationToken) { + // First, add the waiter before checking completion to avoid a race condition. + // This ensures we don't miss a completion notification that happens between + // checking the status and adding the waiter. + var tcs = this.waiters.GetOrAdd(instanceId, _ => new TaskCompletionSource()); + + // Now check if already completed - if so, complete the waiter immediately if (this.store.TryGetValue(instanceId, out SerializedInstanceState? state)) { lock (state) @@ -750,8 +756,8 @@ public Task WaitForInstanceAsync(string instanceId, Cancella statusRecord.OrchestrationStatus == OrchestrationStatus.Failed || statusRecord.OrchestrationStatus == OrchestrationStatus.Terminated) { - // orchestration has already completed - return Task.FromResult(statusRecord); + // Orchestration has already completed - complete the waiter and return + tcs.TrySetResult(statusRecord); } } } @@ -759,7 +765,6 @@ public Task WaitForInstanceAsync(string instanceId, Cancella // Caller will be notified when the instance completes. // The ContinueWith is just to enable cancellation: https://stackoverflow.com/a/25652873/2069 - var tcs = this.waiters.GetOrAdd(instanceId, _ => new TaskCompletionSource()); return tcs.Task.ContinueWith(t => t.GetAwaiter().GetResult(), cancellationToken); } From 8fc24d9b6d79f86348dd3287797a9c890d1bc0aa Mon Sep 17 00:00:00 2001 From: wangbill Date: Wed, 17 Dec 2025 15:01:04 -0800 Subject: [PATCH 3/3] Update src/InProcessTestHost/Sidecar/InMemoryOrchestrationService.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Sidecar/InMemoryOrchestrationService.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/InProcessTestHost/Sidecar/InMemoryOrchestrationService.cs b/src/InProcessTestHost/Sidecar/InMemoryOrchestrationService.cs index 6bb696d6..40691bd9 100644 --- a/src/InProcessTestHost/Sidecar/InMemoryOrchestrationService.cs +++ b/src/InProcessTestHost/Sidecar/InMemoryOrchestrationService.cs @@ -756,8 +756,11 @@ public Task WaitForInstanceAsync(string instanceId, Cancella statusRecord.OrchestrationStatus == OrchestrationStatus.Failed || statusRecord.OrchestrationStatus == OrchestrationStatus.Terminated) { - // Orchestration has already completed - complete the waiter and return - tcs.TrySetResult(statusRecord); + // Orchestration has already completed - complete the waiter and clean it up + if (tcs.TrySetResult(statusRecord)) + { + this.waiters.TryRemove(instanceId, out _); + } } } }