Fix cancellation token race during parser comparison#4280
Conversation
f00dffb to
c5ea90f
Compare
| } | ||
| } | ||
|
|
||
| public ExecutionContext Parent |
| public ExecutionContext Root | ||
| IExecutionContext IExecutionContext.Root => Root; | ||
|
|
||
| private ExecutionContext Root |
There was a problem hiding this comment.
Internally (within this file) we access private members of ExecutionContext.
Publicly, callers only need IExecutionContext
| List<string> StepEnvironmentOverrides { get; } | ||
|
|
||
| ExecutionContext Root { get; } | ||
| ExecutionContext Parent { get; } |
|
|
||
| List<string> StepEnvironmentOverrides { get; } | ||
|
|
||
| ExecutionContext Root { get; } |
There was a problem hiding this comment.
Switched to IExecutionContext for public callers
There was a problem hiding this comment.
Pull request overview
This PR fixes a race condition in PipelineTemplateEvaluatorWrapper.EvaluateAndCompare where a job-level cancellation (which mutates JobContext.Status) occurring between the legacy and new evaluator runs could produce a spurious mismatch. Previously, the step-level CancellationToken was monitored, but this token only fires on step timeout — not on job cancellation. The fix switches to monitoring _context.Root?.CancellationToken (the job-level token) to correctly detect the cancellation race condition.
Changes:
ExecutionContext.cs: PromotesRootto theIExecutionContextinterface (returningIExecutionContextinstead ofExecutionContext), removes the unusedParentproperty from the interface, and adds an explicit interface implementation that delegates to a private concrete-typed property.PipelineTemplateEvaluatorWrapper.cs: Uses_context.Root?.CancellationToken ?? CancellationToken.None(job-level token) instead of_context.CancellationToken(step-level token) to detect cancellation races.- Test file: Updates the existing cancellation test to use
_rootTokenSourcein line with the new logic, adds a new test verifying that root-level cancellation during the legacy evaluator also suppresses mismatch recording, and wires up a mock root context inSetup().
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/Runner.Worker/ExecutionContext.cs |
Exposes Root on the IExecutionContext interface (as IExecutionContext); removes Parent from the interface; adds explicit interface impl with private concrete property |
src/Runner.Worker/PipelineTemplateEvaluatorWrapper.cs |
Switches cancellation detection to the root (job-level) token; adds using System.Threading |
src/Test/L0/Worker/PipelineTemplateEvaluatorWrapperL0.cs |
Adds _rootTokenSource field/setup/teardown; updates existing test to use root token; adds new test for root cancellation in the legacy evaluator path |
c5ea90f to
9c2ac0a
Compare
| // Job cancellation mutates JobContext.Status which expression functions read, | ||
| // so we need the root token to properly detect cancellation between evaluator runs. | ||
| var rootCancellationToken = _context.Root?.CancellationToken ?? CancellationToken.None; | ||
| var cancellationRequestedBefore = rootCancellationToken.IsCancellationRequested; |
There was a problem hiding this comment.
This switches to the job-level cancellation token, which correctly reflects job-cancel.
Working on eliminating differences between old/new copies of the workflow parser/evaluator