From 2ecc0f67feaa447cfb436a043a13e78caba4ccb0 Mon Sep 17 00:00:00 2001 From: nitrobass24 Date: Sun, 23 Aug 2026 20:18:43 -0500 Subject: [PATCH] Don't log the caller's own cancellation as a failed broker request RetryRequest has no cancellation filter, so a cancellation raised by the caller's own token is caught by the general retry handler, logged at ERR with a stack trace, and charged a 5-15s backoff. BrokerMessageListener polls using a linked token it owns and already handles the cancellation itself, cancelling that poll on every Busy -> Idle transition -- that is, on every job completion. ShouldRetryException filters only auth and session exceptions, so the cancellation reaches the general catch. The announced backoff is never served: Task.Delay awaits the same token that was just cancelled, so it throws immediately. The cost is therefore diagnostic rather than latency -- ERR here does not indicate a fault, and the output is indistinguishable from a genuine broker connectivity failure. Rethrow caller-initiated cancellation ahead of the general handler. The IsCancellationRequested guard is deliberate: HttpClient reports a request timeout as TaskCanceledException while the caller's token is uncancelled, and that is a real failure which must keep retrying. --- src/Runner.Common/RunnerService.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Runner.Common/RunnerService.cs b/src/Runner.Common/RunnerService.cs index ccaa83f698f..17fd5320984 100644 --- a/src/Runner.Common/RunnerService.cs +++ b/src/Runner.Common/RunnerService.cs @@ -97,6 +97,16 @@ protected async Task RetryRequest(Func> func, { return await func(); } + // The caller cancelled this request. BrokerMessageListener cancels its own long + // poll on every Busy -> Idle transition and handles the cancellation itself, so + // rethrow instead of logging a failed request: the backoff below awaits this same + // cancelled token, meaning it is announced but never actually served. Guarded on + // IsCancellationRequested because HttpClient reports a request *timeout* as + // TaskCanceledException with the caller's token uncancelled, and that must retry. + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) + { + throw; + } // TODO: Add handling of non-retriable exceptions: https://github.com/github/actions-broker/issues/122 catch (Exception ex) when (attempt < maxAttempts && (shouldRetry == null || shouldRetry(ex))) {