private async Task PruneExpiredMessagesAsync(IRealm realm, CancellationToken stoppingToken) { var clientIds = realm.GetClientIdsWithQueue(); var now = DateTime.UtcNow; var maxDiff = TimeSpan.FromSeconds(10); var seenMap = new Dictionary <string, bool>(); foreach (var clientId in clientIds) { var messageQueue = realm.GetMessageQueueById(clientId); if (messageQueue == null) { continue; } var lastReadDiff = now - messageQueue.GetReadTimestamp(); if (lastReadDiff < maxDiff) { continue; } var messages = messageQueue.GetAll(); foreach (var message in messages) { var seenKey = $"{message.Source}_{message.Destination};"; if (!seenMap.TryGetValue(seenKey, out var seen) || !seen) { var sourceClient = realm.GetClient(message.Source); await realm.HandleMessageAsync(sourceClient, Message.Create(MessageType.Expire, string.Empty), stoppingToken); seenMap[seenKey] = true; } } realm.ClearMessageQueue(clientId); } _logger.LogInformation($"Pruned expired messages for {seenMap.Keys.Count} peers."); }
private async Task PruneZombieConnectionsAsync(IRealm realm) { var clientIds = realm.GetClientIds(); var now = DateTime.UtcNow; var aliveTimeout = TimeSpan.FromSeconds(60); var count = 0; foreach (var clientId in clientIds) { var client = realm.GetClient(clientId); var timeSinceLastHeartbeat = now - client.GetLastHeartbeat(); if (timeSinceLastHeartbeat < aliveTimeout) { continue; } var socket = client.GetSocket(); try { await socket?.CloseAsync($"Zombie connection, time since last heartbeat: {timeSinceLastHeartbeat.TotalSeconds}s"); } finally { realm.ClearMessageQueue(clientId); realm.RemoveClientById(clientId); socket?.Dispose(); } count++; } _logger.LogInformation($"Pruned zombie connections for {count} peers."); }