From 534b00aeb8e31f7e5180e548023511c0784d8edd Mon Sep 17 00:00:00 2001 From: Yinyin Liu Date: Thu, 5 Mar 2026 09:17:06 +0100 Subject: [PATCH] removed accumulating duplicate/stale WebSocket entries over time --- .../Backend/Websockets/WebsockerManager.cs | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/csharp/App/Backend/Websockets/WebsockerManager.cs b/csharp/App/Backend/Websockets/WebsockerManager.cs index 9a6a7dc40..0a8533f94 100644 --- a/csharp/App/Backend/Websockets/WebsockerManager.cs +++ b/csharp/App/Backend/Websockets/WebsockerManager.cs @@ -69,6 +69,9 @@ public static class WebsocketManager var installationConnection = InstallationConnections[installationId]; Console.WriteLine("Update all the connected websockets for installation " + installation.Name); + // Prune dead/closed connections before sending + installationConnection.Connections.RemoveAll(c => c.State != WebSocketState.Open); + var jsonObject = new { id = installationId, @@ -82,20 +85,18 @@ public static class WebsocketManager // Send to all connections concurrently (preserves original fire-and-forget intent), // but isolate failures so one closed socket doesn't affect others or crash the caller. - await Task.WhenAll(connections - .Where(c => c.State == WebSocketState.Open) - .Select(async c => + await Task.WhenAll(connections.Select(async c => + { + try { - try - { - await c.SendAsync(new ArraySegment(dataToSend, 0, dataToSend.Length), - WebSocketMessageType.Text, true, CancellationToken.None); - } - catch (Exception ex) - { - Console.WriteLine($"WebSocket send failed for installation {installationId}: {ex.Message}"); - } - })); + await c.SendAsync(new ArraySegment(dataToSend, 0, dataToSend.Length), + WebSocketMessageType.Text, true, CancellationToken.None); + } + catch (Exception ex) + { + Console.WriteLine($"WebSocket send failed for installation {installationId}: {ex.Message}"); + } + })); } @@ -163,7 +164,10 @@ public static class WebsocketManager }; } - InstallationConnections[installationId].Connections.Add(currentWebSocket); + if (!InstallationConnections[installationId].Connections.Contains(currentWebSocket)) + { + InstallationConnections[installationId].Connections.Add(currentWebSocket); + } var jsonObject = new WebsocketMessage { @@ -197,13 +201,9 @@ public static class WebsocketManager lock (InstallationConnections) { //When the front-end terminates the connection, the following code will be executed - //Console.WriteLine("The connection has been terminated"); foreach (var installationConnection in InstallationConnections) { - if (installationConnection.Value.Connections.Contains(currentWebSocket)) - { - installationConnection.Value.Connections.Remove(currentWebSocket); - } + installationConnection.Value.Connections.RemoveAll(ws => ws == currentWebSocket); } } @@ -224,6 +224,15 @@ public static class WebsocketManager catch (Exception ex) { Console.WriteLine("WebSocket error: " + ex.Message); + + // Ensure stale socket is removed even on unexpected errors + lock (InstallationConnections) + { + foreach (var installationConnection in InstallationConnections) + { + installationConnection.Value.Connections.RemoveAll(ws => ws == currentWebSocket); + } + } } }