Skip to content

Commit 141aaed

Browse files
committed
Work around Kestrel bug that could cause test hangs
1 parent 3109e85 commit 141aaed

1 file changed

Lines changed: 15 additions & 4 deletions

File tree

tests/ModelContextProtocol.AspNetCore.Tests/Utils/KestrelInMemoryConnection.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,21 @@ private class DuplexStream(IDuplexPipe duplexPipe, CancellationTokenSource conne
6565
public override bool CanWrite => true;
6666
public override bool CanSeek => false;
6767

68-
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
69-
=> _readStream.ReadAsync(buffer, offset, count, cancellationToken);
70-
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
71-
=> _readStream.ReadAsync(buffer, cancellationToken);
68+
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
69+
{
70+
// Normally, Kestrel will trigger RequestAborted when the connectionClosedCts fires causing it to gracefully close
71+
// the connection. However, there's currently a race condition that can cause this to get missed. This at least
72+
// unblocks HttpConnection.SendAsync when it disposes the underlying connection stream while awaiting the _readAheadTask
73+
// as would happen with a real socket. https://github.com/dotnet/aspnetcore/pull/62385
74+
using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, connectionClosedCts.Token);
75+
return await _readStream.ReadAsync(buffer, offset, count, linkedTokenSource.Token);
76+
}
77+
78+
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
79+
{
80+
using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, connectionClosedCts.Token);
81+
return await _readStream.ReadAsync(buffer, linkedTokenSource.Token);
82+
}
7283

7384
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
7485
=> _writeStream.WriteAsync(buffer, offset, count, cancellationToken);

0 commit comments

Comments
 (0)