Use WaitAsync to abandon handlers that ignore CancellationToken
Root cause found via diagnostics: the handler call at 16:27:19 never returned. Guard: processing message X logged, but Guard: processed never appeared. The 55s CancellationToken fired but the handler ignored it (blocked on a non-cancelable StackExchange.Redis operation or DB query that uses its own timeout). Fix: Replace await handler(token) with handler(token).WaitAsync(token). WaitAsync returns when EITHER the handler completes OR the token fires, regardless of whether the handler cooperatively checks the token. The abandoned handler continues in background but the consumer loop resumes immediately. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -714,7 +714,10 @@ public sealed class MessagingTransportClient : ITransportClient, IMicroserviceTr
|
||||
timeoutCts.CancelAfter(TimeSpan.FromSeconds(55));
|
||||
|
||||
_logger.LogWarning("[DIAG] Guard: processing message {MessageId}", lease.MessageId);
|
||||
await handler(lease, timeoutCts.Token);
|
||||
// WaitAsync abandons handlers that ignore CancellationToken (e.g.,
|
||||
// StackExchange.Redis commands with their own internal timeout).
|
||||
// The handler continues in background but the consumer loop is unblocked.
|
||||
await handler(lease, timeoutCts.Token).WaitAsync(timeoutCts.Token);
|
||||
sw.Stop();
|
||||
_logger.LogWarning("[DIAG] Guard: message {MessageId} processed in {ElapsedMs}ms", lease.MessageId, sw.ElapsedMilliseconds);
|
||||
await lease.AcknowledgeAsync(cancellationToken);
|
||||
|
||||
@@ -395,7 +395,8 @@ public sealed class MessagingTransportServer : ITransportServer, IDisposable
|
||||
using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
timeoutCts.CancelAfter(TimeSpan.FromSeconds(55)); // 55s < 60s gateway timeout
|
||||
|
||||
await handler(lease, timeoutCts.Token);
|
||||
// WaitAsync abandons handlers that ignore CancellationToken.
|
||||
await handler(lease, timeoutCts.Token).WaitAsync(timeoutCts.Token);
|
||||
await lease.AcknowledgeAsync(cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
|
||||
|
||||
Reference in New Issue
Block a user