Description
The Helix Job Monitor can spend hours draining Azure DevOps test-result uploads after all Helix jobs have completed, while the normal ℹ️ Status heartbeat stops entirely. This makes a very slow or stuck upload indistinguishable from a hung monitor and provides no indication of which uploads remain or what phase they are in.
Example: runtime build 1542847, first Monitor Helix Jobs attempt
Raw log timeline
All times are UTC from the raw AzDO log:
15:45:24 - monitor starts using Microsoft.DotNet.Helix.JobMonitor 11.0.0-beta.26404.8 (Arcade commit 35ea7e6192f7ab5fddd068ea9ce3f5e3d5491298).
19:30:16.155 - last aggregate status: 31 processed / 41 completed jobs and 1763 processed / 2958 completed work items.
19:30:16.157 - Waiting for 10 pending test result upload(s) to complete.
19:30:18 - one of those uploads completes.
20:02:47, 20:16:52, 20:37:26, 20:50:07 - four more uploads complete. Their total upload-processing durations were approximately 180, 187, 203, and 207 minutes.
- No further monitor output occurs until
21:07:31, when AzDO cancels the operation. Five uploads never reported completion.
The five jobs still lacking a test results ... processed line at cancellation were:
Libraries Test Run checked coreclr windows x86 Debug (47f2f958-37c8-4662-922b-7f48d3abad94), processing since 17:27:36
ios-arm64 Release AllSubsets_CoreCLR_Smoke (208fe8d1-d1e1-447a-b181-51162b422338), since 17:28:42
Libraries Test Run checked coreclr windows x64 Release (f92dc6d3-0b17-4f34-9a9c-232c6f915565), since 17:34:29
Libraries Test Run checked coreclr osx arm64 Debug (4ce2007f-3914-4c9d-af2a-0674e80815ef), since 18:17:28
osx-arm64 release Installer_Build_And_Test (e2fd1085-9828-4a73-9456-ab9cb75188a4), since 18:25:48
The last status line is only 2 ms before TestResultUploadQueue.DrainAsync logs its pending count. DrainAsync then awaits Task.WhenAll(_pending) and does not invoke StatusReporter, so the absence of status updates is deterministic rather than an AzDO log-loss issue.
Version / possible existing fix
This build's monitor package points to Arcade commit 35ea7e6 from August 4. #17256, Fix Helix test result upload retries, merged on August 6 after this monitor invocation had started. It adds retries for transient Azure DevOps transport failures, HttpClient timeout cancellations, and 5xx/429 responses, so it may mitigate the underlying upload problem once consumed.
However, the merged implementation still logs only once before Task.WhenAll in DrainAsync; it does not provide a heartbeat or identify long-running uploads. Therefore the observability problem remains even if #17256 fixes this particular transport failure.
Expected behavior
While draining result uploads, the monitor should periodically report progress, including at minimum:
- pending upload count and elapsed drain time;
- names/IDs and elapsed time of uploads still pending;
- ideally the current phase for each upload (download Helix results, create test run, publish result batches/attachments, complete test run);
- warnings or bounded behavior when an individual operation or the overall drain exceeds an expected duration.
This would make it possible to distinguish slow Azure DevOps ingestion, throttling/retries, and a genuinely stuck request, and would preserve the monitor's normal status heartbeat through its final phase.
Description
The Helix Job Monitor can spend hours draining Azure DevOps test-result uploads after all Helix jobs have completed, while the normal
ℹ️ Statusheartbeat stops entirely. This makes a very slow or stuck upload indistinguishable from a hung monitor and provides no indication of which uploads remain or what phase they are in.Example: runtime build 1542847, first
Monitor Helix JobsattemptRaw log timeline
All times are UTC from the raw AzDO log:
15:45:24- monitor starts usingMicrosoft.DotNet.Helix.JobMonitor 11.0.0-beta.26404.8(Arcade commit35ea7e6192f7ab5fddd068ea9ce3f5e3d5491298).19:30:16.155- last aggregate status:31 processed / 41 completedjobs and1763 processed / 2958 completedwork items.19:30:16.157-Waiting for 10 pending test result upload(s) to complete.19:30:18- one of those uploads completes.20:02:47,20:16:52,20:37:26,20:50:07- four more uploads complete. Their total upload-processing durations were approximately 180, 187, 203, and 207 minutes.21:07:31, when AzDO cancels the operation. Five uploads never reported completion.The five jobs still lacking a
test results ... processedline at cancellation were:Libraries Test Run checked coreclr windows x86 Debug(47f2f958-37c8-4662-922b-7f48d3abad94), processing since17:27:36ios-arm64 Release AllSubsets_CoreCLR_Smoke(208fe8d1-d1e1-447a-b181-51162b422338), since17:28:42Libraries Test Run checked coreclr windows x64 Release(f92dc6d3-0b17-4f34-9a9c-232c6f915565), since17:34:29Libraries Test Run checked coreclr osx arm64 Debug(4ce2007f-3914-4c9d-af2a-0674e80815ef), since18:17:28osx-arm64 release Installer_Build_And_Test(e2fd1085-9828-4a73-9456-ab9cb75188a4), since18:25:48The last status line is only 2 ms before
TestResultUploadQueue.DrainAsynclogs its pending count.DrainAsyncthen awaitsTask.WhenAll(_pending)and does not invokeStatusReporter, so the absence of status updates is deterministic rather than an AzDO log-loss issue.Version / possible existing fix
This build's monitor package points to Arcade commit
35ea7e6from August 4. #17256, Fix Helix test result upload retries, merged on August 6 after this monitor invocation had started. It adds retries for transient Azure DevOps transport failures,HttpClienttimeout cancellations, and 5xx/429 responses, so it may mitigate the underlying upload problem once consumed.However, the merged implementation still logs only once before
Task.WhenAllinDrainAsync; it does not provide a heartbeat or identify long-running uploads. Therefore the observability problem remains even if #17256 fixes this particular transport failure.Expected behavior
While draining result uploads, the monitor should periodically report progress, including at minimum:
This would make it possible to distinguish slow Azure DevOps ingestion, throttling/retries, and a genuinely stuck request, and would preserve the monitor's normal status heartbeat through its final phase.