using Microsoft.AspNetCore.SignalR; namespace ZB.MOM.WW.MxGateway.Server.Dashboard.Hubs; /// /// Time-bounded SignalR send shared by the dashboard hub publishers. A group or /// broadcast send completes only once every target connection has accepted the /// frame, so one remote viewer with a full transport buffer would otherwise hold /// the publisher's single drain loop for as long as that viewer stays slow. /// internal static class BoundedHubSend { /// /// Sends as and waits at most /// for it. The timeout cancels the send's own token, so /// the lifetime manager abandons the pending write to the slow connection, and the /// wait itself is bounded too, so a proxy that ignores the token cannot stall the /// caller either. /// /// Target client proxy (a group or all connections). /// Client method name. /// The single message argument. /// Upper bound on the send. /// Host shutdown token; its cancellation propagates. /// /// when the send completed in time; /// when it was abandoned at the timeout. /// /// was cancelled. public static async Task SendAsync( IClientProxy proxy, string method, object argument, TimeSpan timeout, CancellationToken stoppingToken) { using CancellationTokenSource bounded = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken); bounded.CancelAfter(timeout); try { await proxy.SendAsync(method, argument, bounded.Token) .WaitAsync(bounded.Token) .ConfigureAwait(false); return true; } catch (OperationCanceledException) when (!stoppingToken.IsCancellationRequested) { return false; } } }