diff --git a/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportClient.cs b/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportClient.cs index b2e1012e2..1d72a7e29 100644 --- a/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportClient.cs +++ b/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportClient.cs @@ -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); diff --git a/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportServer.cs b/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportServer.cs index dbc24b23d..2f584b14a 100644 --- a/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportServer.cs +++ b/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportServer.cs @@ -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)