Skip to content

Commit 3b1dc42

Browse files
authored
CSHARP-5661: Fix UnobservedTaskException on socket connecting timeout (#1742)
1 parent de601bc commit 3b1dc42

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

src/MongoDB.Driver/Core/Connections/TcpStreamFactory.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,11 @@ private async Task ConnectAsync(Socket socket, EndPoint endPoint, CancellationTo
164164

165165
if (!connectTask.IsCompleted)
166166
{
167-
try { socket.Dispose(); } catch { }
167+
try
168+
{
169+
connectTask.IgnoreExceptions();
170+
socket.Dispose();
171+
} catch { }
168172

169173
cancellationToken.ThrowIfCancellationRequested();
170174
throw new TimeoutException($"Timed out connecting to {endPoint}. Timeout was {_settings.ConnectTimeout}.");

tests/MongoDB.Driver.Tests/Core/Connections/TcpStreamFactoryTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,43 @@ public void CreateStream_should_connect_to_a_running_server_and_return_a_non_nul
185185
stream.Should().NotBeNull();
186186
}
187187

188+
[Fact]
189+
public async Task CreateStream_should_not_produce_unobserved_exceptions_on_timeout()
190+
{
191+
// The purpose of this test is to attempt a connection that will reliably be rejected and throw exception the connection.
192+
// By specifying a very short timeout, we expect a TimeoutException to occur before the connection exception.
193+
// This test ensures that the connection exception is observed.
194+
var subject = new TcpStreamFactory(new TcpStreamSettings(connectTimeout: TimeSpan.FromMilliseconds(1)));
195+
var endpoint = new IPEndPoint(IPAddress.Parse("1.1.1.1"), 23456);
196+
197+
GC.Collect();
198+
GC.WaitForPendingFinalizers();
199+
var unobservedTaskExceptionRaised = false;
200+
201+
EventHandler<UnobservedTaskExceptionEventArgs> eventHandler = (s, args) =>
202+
{
203+
unobservedTaskExceptionRaised = true;
204+
};
205+
206+
TaskScheduler.UnobservedTaskException += eventHandler;
207+
208+
try
209+
{
210+
var exception = await Record.ExceptionAsync(() => subject.CreateStreamAsync(endpoint, CancellationToken.None));
211+
exception.Should().BeOfType<TimeoutException>();
212+
213+
Thread.Sleep(100);
214+
GC.Collect();
215+
GC.WaitForPendingFinalizers();
216+
}
217+
finally
218+
{
219+
TaskScheduler.UnobservedTaskException -= eventHandler;
220+
}
221+
222+
unobservedTaskExceptionRaised.Should().BeFalse();
223+
}
224+
188225
[Theory]
189226
[ParameterAttributeData]
190227
public void SocketConfigurator_can_be_used_to_set_keepAlive(

0 commit comments

Comments
 (0)