Fixed listener loop dying on ChannelClosedException#4
Conversation
…ue to ChannelClosedException.
|
|
||
| // Write to client. | ||
| await client.Pipeline.Writer.WriteAsync(data.Buffer); | ||
| client.Pipeline.Writer.TryWrite(data.Buffer); |
There was a problem hiding this comment.
I'm not sure what the advantage of this change is. If TryWrite could not write the results back, don't we need to handle this?
There was a problem hiding this comment.
The intention was to ensure that the loop does not stop even if an issue occurs.
In fact, I believe there is no problem because TryWrite returns false only when the write operation has already been completed.
https://github.com/dotnet/runtime/blob/main/src/libraries/System.Threading.Channels/src/System/Threading/Channels/UnboundedChannel.cs#L256
There was a problem hiding this comment.
Ah I see, it returns false when the other side of the pipeline has been closed. I'll give a build with this a shot on my server, see how it flies, then merge this PR
In UdpConnectionListener, the try/catch block surrounding the receiving while loop is located outside the loop. If ProcessData throws an exception, the entire loop unwinds, logging "Listen loop error" once before ListenAsync terminates. Since there is no restart mechanism and there is only one loop per shared UDP socket, all lobbies on the server become unable to receive packets.
While this usually has no impact, a defect occurs in very rare cases.
The trigger is a race condition within ProcessData:
If the connection in question is disposed between steps 1 and 2 (due to a kick, leaving, or a keep-alive timeout calling Pipeline.Writer.Complete()), step 2 results in a write to a closed channel, throwing a ChannelClosedException.