Repository navigation
Continue consistent application of optional cancellation tokens - #5729
Merged
Merged
Conversation
johnsimons
force-pushed
the
john/cancel_part2
branch
from
August 11, 2026 02:36
ada2e74 to
85741c4
Compare
johnsimons
marked this pull request as ready for review
August 11, 2026 04:07
rbev
approved these changes
Aug 11, 2026
Expands the scope of `CancellationToken` parameters across the codebase, standardizing their naming and making them optional where appropriate. This further reduces cancellation analyzer debt by removing suppressions from `.editorconfig` files and adding pragmas for interface limitations.
johnsimons
force-pushed
the
john/cancel_part2
branch
from
August 11, 2026 07:17
85741c4 to
ea21c45
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Third step in threading
CancellationTokenthrough the platform. The two host projects,ServiceControlandServiceControl.Audit, carried 260 of the tracked cancellation diagnosticsbetween them. This PR retires 253 of them: every controller action, hosted service, message handler
and mid-layer method now takes and forwards a token down to the persistence boundary.
Persistence interfaces themselves are unchanged and come next; tokens added here mostly terminate at
the data store call, which is the expected shape at this stage.
What this does
Applies the same convention as the previous PRs: non-private members take
CancellationToken cancellationToken = defaultlast, private helpers take it required, namedcancellationTokenthroughout.HttpContext.RequestAborted.IMessageSessionsends,
IDomainEvents.Raiseand the scatter-gather fan-out all receive it.stoppingToken/ the startup token. SeveralIAsyncTimercallbacks werediscarding the token the timer already handed them (
_ =>); they now use it, which is what Phase 1'sAsyncTimerchange was for.context.CancellationToken.NSB0002enforces this automaticallyonce the callee accepts one.
RetriesGateway,RetryProcessor,RetryingManager,InMemoryRetry,RetryDocumentManager), the error and audit ingestion pipelines, endpointmonitoring, custom checks, external integrations, notifications and the platform-connection providers.
IEndpointInstanceMonitoringwas pulled forward from the persistence phase: it lives inServiceControl.Persistencebut is implemented inServiceControl, so it had to move with itsimplementation. That retires 5 of that project's diagnostics early.
Debt blocks narrowed, not deleted
Both hosts keep an
.editorconfigblock, but scoped to named files rather than the whole project:ServiceControlgoes from 8 rules project-wide to 3 rules on 5 files,ServiceControl.Auditfrom 7 to2 rules on 4 files. Each block records what it is waiting on:
TransportCustomization.CreateTransportInfrastructuretakingFunc<string, Exception, Task>foronCriticalErrorErrorIngestion,ErrorIngestionFaultPolicy,ImportFailureCircuitBreaker(both hosts)IRetryBatchStorecallbacks typedFunc<string, DateTime, Task>RetriesGatewayIExternalIntegrationRequestsDataStore.SubscribetypedFunc<object[], Task>EventDispatcherHostedServiceIFailedAuditStorage.ProcessFailedMessageshanding its callback a separate token thatPS0020cannot seeImportFailedAuditsOne is not an interface problem:
RetriesGateway.AssignMessagesToBatchis private and should take arequired token, but its trailing optional parameters make that illegal. It needs a parameter reorder,
which didn't belong in this diff.
Bug fixed along the way
ScatterGatherApi.FetchAndParsecaughtOperationCanceledExceptionwith the comment "Intentional,used to gracefully handle timeout" and returned an empty result for that remote. Once a token flows
in, a client disconnect and an
HttpClienttimeout arrive as the same exception type, so an abandonedrequest would have been reported as "that remote timed out" and quietly excluded from the aggregate.
It now rethrows when the caller's token is cancelled and only absorbs genuine per-remote timeouts.
Notes for reviewers
catch (Exception e)followed byif (e is OperationCanceledException && token.IsCancellationRequested). These are now a filteredcatch (OperationCanceledException)ahead of the general handler. Behaviour is preserved exactly,including signalling every in-flight message context before breaking out of the batch loop.
IModelBinder.BindModelAsync,ASP.NET middleware
InvokeAsync, the NServiceBus critical-error delegate).PS0018is unsatisfiablethere, so they carry site-level pragmas with justifications rather than fixes, same as the ASP.NET
auth interfaces in the previous PR.
HttpApiRoutesapproval test changed and this is expected. It snapshots the route tableincluding parameter lists, so every action picked up
, CancellationToken cancellationToken. Beforeaccepting the new snapshot I checked mechanically that stripping the token parameters from the
received file makes it byte-identical to the approved one: zero residual differences, so no route,
no HTTP verb and no existing parameter changed.
FaultyPublisher,CustomRetriesGateway,CustomRetryDocumentManager,MockEndpointInstanceMonitoring,TestApi.