Close sessions for lost WebSockets to prevent zombie SyncPlay groups (#17079)
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
Format / format-check (push) Has been cancelled
Tests / run-tests (macos-latest) (push) Has been cancelled
Tests / run-tests (ubuntu-latest) (push) Has been cancelled
Tests / run-tests (windows-latest) (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Artifact (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Unstable Spec (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Stable Spec (push) Has been cancelled
Project Automation / Project board (push) Has been cancelled
Merge Conflict Labeler / main (push) Has been cancelled
Stale PR Check / Check PRs with merge conflicts (push) Has been cancelled

Close sessions for lost WebSockets to prevent zombie SyncPlay groups
This commit is contained in:
Enea D'Angiò
2026-07-02 19:36:48 +02:00
committed by GitHub
parent 379c58a48d
commit 8f3eb3205d
3 changed files with 159 additions and 2 deletions

View File

@@ -127,8 +127,12 @@ namespace Emby.Server.Implementations.HttpServer
{
receiveResult = await _socket.ReceiveAsync(memory, cancellationToken).ConfigureAwait(false);
}
catch (WebSocketException ex)
catch (Exception ex) when (ex is WebSocketException or ObjectDisposedException or OperationCanceledException)
{
// ObjectDisposedException/OperationCanceledException: the socket was torn
// down underneath us (e.g. by the keep-alive watchdog after the connection
// was declared lost). Fall through so Closed is still raised and the
// session can release this connection.
_logger.LogWarning("WS {IP} error receiving data: {Message}", RemoteEndPoint, ex.Message);
break;
}

View File

@@ -246,8 +246,21 @@ namespace Emby.Server.Implementations.Session
_logger.LogInformation("Lost {0} WebSockets.", lost.Count);
foreach (var webSocket in lost)
{
// TODO: handle session relative to the lost webSocket
RemoveWebSocket(webSocket);
// The connection stopped answering keep-alives, so a close frame will
// never arrive and the pending receive loop would hang forever, keeping
// the session (and e.g. its SyncPlay group membership) alive. Disposing
// the connection aborts the receive loop, which raises Closed and lets
// the session end normally.
try
{
webSocket.Dispose();
}
catch (Exception exception)
{
_logger.LogWarning(exception, "Error disposing lost WebSocket from {RemoteEndPoint}.", webSocket.RemoteEndPoint);
}
}
}
}