async Task SendPriorityAsync(HubMethodCall msg) { if (RequireSendConfirmation) { await conn.InvokeCoreAsync(msg.MethodName, msg.Args); } else { priority.Enqueue(msg); flushes.Add(Flush()); } }
async Task Flush() { try { await flushing.WaitAsync(); if (flushCancellation.IsCancellationRequested) { return; } HubMethodCall priorityMethod = null, standardMethod = null; while (priority.TryPeek(out priorityMethod) || standard.TryPeek(out standardMethod)) { while (conn.State != HubConnectionState.Connected && !flushCancellation.IsCancellationRequested) { await Task.Delay(MinDelay); } if (flushCancellation.IsCancellationRequested) { break; } bool dequeued = false; bool isPriority = priorityMethod != null; var method = priorityMethod ?? standardMethod; try { method.Attempts++; if (!RequireSendConfirmation && (method.MethodName == nameof(ItemResult) || method.MethodName == nameof(Log))) { await conn.SendCoreAsync(method.MethodName, method.Args); } else { await conn.InvokeCoreAsync(method.MethodName, method.Args); } dequeued = isPriority ? priority.TryDequeue(out _) : standard.TryDequeue(out _); } catch (Exception ex) { if (method.Attempts > 3) { logger.LogError(ex, $"Message discarded after 3 attempts: {method.MethodName}"); if (!dequeued) { _ = isPriority ? priority.TryDequeue(out _) : standard.TryDequeue(out _); } } else { int retryDelay = new Random().Next(0, 5) * MinDelay; logger.LogWarning(ex, "Could not send {method} message to server. Will retry in {retryDelay}ms.", method.MethodName, retryDelay); await Task.Delay(retryDelay); } } priorityMethod = null; standardMethod = null; } } finally { flushing.Release(); } }