From e061c35916f40c56fbffea0fdae31a0c53159f2b Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Mon, 23 Jun 2025 16:35:32 -0500 Subject: [PATCH 1/3] Improve disposal logic in AsyncWebsocketMessageResultEnumerator to prevent multiple disposals --- .../Internal/AsyncWebsocketMessageEnumerator.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs b/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs index 906823ff0..215f6ce1a 100644 --- a/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs +++ b/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs @@ -14,6 +14,7 @@ internal partial class AsyncWebsocketMessageResultEnumerator : IAsyncEnumerator< private readonly CancellationToken _cancellationToken; private readonly WebSocket _webSocket; private readonly byte[] _receiveBuffer; + private bool _disposed = false; public AsyncWebsocketMessageResultEnumerator(WebSocket webSocket, CancellationToken cancellationToken) { @@ -26,8 +27,12 @@ public AsyncWebsocketMessageResultEnumerator(WebSocket webSocket, CancellationTo public ValueTask DisposeAsync() { - ArrayPool.Shared.Return(_receiveBuffer); - _webSocket?.Dispose(); + if (!_disposed) + { + ArrayPool.Shared.Return(_receiveBuffer); + _webSocket?.Dispose(); + _disposed = true; + } return new ValueTask(Task.CompletedTask); } From 1cf836b06d7a5b3e715de7ad72c2f930d1d4e5b6 Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Tue, 24 Jun 2025 09:37:54 -0500 Subject: [PATCH 2/3] fb --- .../Internal/AsyncWebsocketMessageEnumerator.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs b/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs index 215f6ce1a..5cdee89c8 100644 --- a/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs +++ b/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs @@ -13,8 +13,7 @@ internal partial class AsyncWebsocketMessageResultEnumerator : IAsyncEnumerator< public ClientResult Current { get; private set; } private readonly CancellationToken _cancellationToken; private readonly WebSocket _webSocket; - private readonly byte[] _receiveBuffer; - private bool _disposed = false; + private byte[] _receiveBuffer; public AsyncWebsocketMessageResultEnumerator(WebSocket webSocket, CancellationToken cancellationToken) { @@ -27,12 +26,11 @@ public AsyncWebsocketMessageResultEnumerator(WebSocket webSocket, CancellationTo public ValueTask DisposeAsync() { - if (!_disposed) + if (Interlocked.Exchange(ref _receiveBuffer, null) is byte[] toReturn) { - ArrayPool.Shared.Return(_receiveBuffer); - _webSocket?.Dispose(); - _disposed = true; + ArrayPool.Shared.Return(toReturn); } + _webSocket?.Dispose(); return new ValueTask(Task.CompletedTask); } From 6699f3997b32f16c818291f8c5336a0fb7c7ab4e Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Tue, 24 Jun 2025 09:48:38 -0500 Subject: [PATCH 3/3] Update src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs Co-authored-by: Stephen Toub --- .../Internal/AsyncWebsocketMessageEnumerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs b/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs index 5cdee89c8..e89d9a910 100644 --- a/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs +++ b/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs @@ -31,7 +31,7 @@ public ValueTask DisposeAsync() ArrayPool.Shared.Return(toReturn); } _webSocket?.Dispose(); - return new ValueTask(Task.CompletedTask); + return default; } public async ValueTask MoveNextAsync()