Repository navigation
Thread cancellation through 9 Health Parser web reads (#4203) - #4359
Merged
Merged
Conversation
get_health_parser_cpu_tasks, _io_issues, _memory_broker, _memory_conditions, _memory_node_oom, _scheduler_issues, _severe_errors, _significant_waits and _system_health now take a CancellationToken and pass it down to every store call (resolver, shared CollectAsync/EmptyAsync helpers, the significant-waits direct path, the not-collected probe), so an abandoned web request stops its query instead of running to completion. Removes all nine from CancellationAllowlist.
erikdarlingdata
marked this pull request as ready for review
September 26, 2026 00:28
This was referenced Sep 26, 2026
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.
Refs #4203.
Why
Web
/api/read/*handlers must threadRequestAbortedinto the store query so an abandoned browser request stops its work instead of running to completion. The nineget_health_parser_*tools were still onCancellationAllowlist, meaning their store calls ran underCancellationToken.Noneregardless of the request.What changes
DarlingMcpHealthParserTools.cs: every one of the nine health-parser tools (GetSystemHealth,GetSevereErrors,GetIOIssues,GetSchedulerIssues,GetMemoryConditions,GetCPUTasks,GetMemoryBroker,GetMemoryNodeOOM,GetSignificantWaits) now takes a trailingCancellationToken cancellationToken = defaultand threads it through every store call in its body:DarlingServerResolver.ResolveOrErrorAsync, the sharedCollectAsync/EmptyAsynchelpers,DarlingSystemHealthReader.ReadEventXmlAsync/GetLastCaptureAsync/GetLastCaptureOfTypeAsync/GetDatabaseNameMapAsync, andDarlingEngineCapability.NotCollectedStatusAsync. Eachcatch (Exception ex)narrows towhen (ex is not OperationCanceledException)so a cancellation propagates instead of being swallowed into an error payload.DarlingWebEndpoints.cs: the nine tools are removed fromCancellationAllowlist; their dispatch-table entries now passcancellationToken: c.RequestAborted.All nine tools in scope for #4203's health-parser slice are done; nothing was left for a follow-up slice.
Test plan
dotnet build Darling/Darling.Tests/Darling.Tests.csproj -p:EnableWindowsTargeting=true- 0 Warning(s), 0 Error(s)WebReadCancellationPinTests,PgTargetMcpSurfaceTests,McpServiceParameterDiSeatCensusTests,EngineCapabilityReadWiringTests,RuntimePreconditionReadWiringTests(net10.0-windows only, cannot run on macOS - CI decides these)For the coordinator
CancellationAllowlistshrinks by 9 in this PR (from the pre-#4203 baseline). This edits the same block ofDarlingWebEndpoints.cs(CancellationAllowlistarray and the read-dispatch table) that sibling #4203 slice PRs also touch, so this PR's diff will conflict textually with those siblings and needs manual resolution at merge time, not a rebase onto them per the brief.CHANGELOG entry
SECTION: Fixed
ENTRY:
get_health_parser_*/api/readhandlers ran their Postgres queries to completion even after the browser tab closed or the request was aborted; they now threadRequestAbortedthrough every store call so an abandoned read stops promptly.REF:
[Thread cancellation through 9 Health Parser web reads (#4203) #4359]: Thread cancellation through 9 Health Parser web reads (#4203) #4359
pm-pr lane report (dev merge + verification)
Merge: new head
58062b0a2cf61a287936b29f46928ce913bfb2d2, a plain merge oforigin/dev(no rebase, no force push). Auto-merge was clean — git reported no conflicted files;DarlingWebEndpoints.cs'sCancellationAllowlistand dispatch table merged automatically because dev's #4357 slice (trend tools) and this PR's #4203 slice (health-parser tools) touched disjoint entries in both the set literal and the dispatch table.Allowlist check (110 -> 101): extracted the quoted names in
CancellationAllowlistatorigin/dev(110) and at the merged head (101). Diff shows exactly the 9get_health_parser_*names removed (system_health,severe_errors,io_issues,scheduler_issues,memory_conditions,cpu_tasks,memory_broker,memory_node_oom,significant_waits) and nothing added. PASS.Build:
dotnet build Darling/Darling.Tests/Darling.Tests.csproj -p:EnableWindowsTargeting=true— Build succeeded, 0 Warning(s), 0 Error(s).Verification
[McpServerTool]bodies inDarlingMcpHealthParserTools.cs. Every store call —DarlingServerResolver.ResolveOrErrorAsync,CollectAsync,EmptyAsync,DarlingSystemHealthReader.ReadEventXmlAsync/GetLastCaptureAsync/GetLastCaptureOfTypeAsync/GetDatabaseNameMapAsync, andDarlingEngineCapability.NotCollectedStatusAsync— takes and forwardscancellationToken.grep -n "CancellationToken.None"on the file returns nothing.catch (Exception ex) when (ex is not OperationCanceledException).WebReadCancellationPinTests: reflects[McpServerTool]methods viaAssembly.GetTypes()/GetMethods, scoped toDarlingWebEndpoints.BuildReadDispatch().Keys. Asserts every store-reading tool method not on the allowlist takes aCancellationToken, and that no allowlist entry already has one (CancellationAllowlist_HasNoStaleEntry). New shapes pass: all 9 tools have the token and are off the allowlist.PgTargetMcpSurfaceTests: buildsRegisteredToolsfrom attribute names across assemblies; unaffected by this change (no tool added/removed, just token param).McpServiceParameterDiSeatCensusTests: checks DI seat registration by service-parameter type; unaffected (no new parameter types).EngineCapabilityReadWiringTests/RuntimePreconditionReadWiringTests: regex-scan MCP source forNotCollectedStatusAsync(...)/RuntimePrecondition.StatusAsync(...)calls, with a documented negative-lookahead guard so a trailingcancellationTokentoken argument isn't mis-captured as the collector name (both regexes' comments cite Web /api/read/* handlers never thread RequestAborted into the underlying store query #4203 explicitly for this).EmptyAsync'sNotCollectedStatusAsync(postgres, c.ServerId, c.ServerName, SystemHealthCollectorName, cancellationToken)call matches the guarded pattern correctly (collector name isSystemHealthCollectorName, token argument recognized and excluded).RequestAborted).REF:link ishttps://github.com/erikdarlingdata/PerformanceMonitor/pull/4359— correct PR. Body leads withRefs #4203., not Closes. No edit needed.Darling.Teststargetsnet10.0-windowsand requiresMicrosoft.WindowsDesktop.App(confirmed viadotnet vstestfailing with "No frameworks were found" on this macOS arm64 host). CI's Windows build job decides all 5 test classes above plus the full suite.