Skip to content

Commit afae3ed

Browse files
thomhurstclaude
andcommitted
fix: resolve flaky EngineCancellationTokenTests by handling scheduler cancellation
When a module fails and the pipeline is cancelled, the scheduler throws OperationCanceledException from WaitForNextSchedulingOpportunity. This exception was not being caught, causing RegisterTerminatedResultsForCancelledModules to be skipped. Dependent modules never got their results registered, causing the test to intermittently fail. The fix catches OperationCanceledException from the scheduler task when it's caused by a module failure (firstException != null), allowing the result registration to proceed correctly. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4699707 commit afae3ed

2 files changed

Lines changed: 12 additions & 4 deletions

File tree

src/ModularPipelines/Engine/ModuleExecutor.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,17 @@ private async Task<IEnumerable<IModule>> ExecuteWithSchedulerAsync(
129129
EnsureCancellation(cancellationTokenSource);
130130
}
131131

132-
await schedulerTask.ConfigureAwait(false);
132+
try
133+
{
134+
await schedulerTask.ConfigureAwait(false);
135+
}
136+
catch (OperationCanceledException) when (firstException != null)
137+
{
138+
// Expected when cancellation was triggered due to module failure.
139+
// The scheduler throws OperationCanceledException from WaitForNextSchedulingOpportunity
140+
// when the cancellation token is cancelled.
141+
_logger.LogDebug("Scheduler cancelled due to module failure");
142+
}
133143

134144
_logger.LogDebug("All modules completed");
135145

test/ModularPipelines.UnitTests/Execution/EngineCancellationTokenTests.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,7 @@ public async Task When_Cancel_Engine_Token_With_DependsOn_Then_Modules_Cancel()
6767

6868
await Assert.That(async () => await host.ExecutePipelineAsync()).ThrowsException();
6969

70-
// Allow time for all module results to be finalized after pipeline termination
71-
await Task.Delay(TimeSpan.FromSeconds(1));
72-
70+
// Results should be registered before the exception is thrown, no delay needed
7371
var module1Result = resultRegistry.GetResult(typeof(Module1));
7472
// Module1 depends on BadModule which failed, so Module1 should be marked as PipelineTerminated
7573
await Assert.That(module1Result).IsNotNull();

0 commit comments

Comments
 (0)