Skip to content

Commit d8ab2f1

Browse files
CSHARP-3462: Unobserved task exception on connection failure raises its head again (#492)
1 parent 282965f commit d8ab2f1

File tree

2 files changed

+64
-6
lines changed

2 files changed

+64
-6
lines changed

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ private IByteBuffer ReceiveBuffer(int responseTo, CancellationToken cancellation
357357
Task.WaitAny(messageTask, receiveLockRequest.Task);
358358
if (messageTask.IsCompleted)
359359
{
360-
return _dropbox.RemoveMessage(responseTo);
360+
return _dropbox.RemoveMessage(responseTo); // also propagates exception if any
361361
}
362362

363363
receiveLockRequest.Task.GetAwaiter().GetResult(); // propagate exceptions
@@ -371,12 +371,11 @@ private IByteBuffer ReceiveBuffer(int responseTo, CancellationToken cancellation
371371
catch (Exception ex)
372372
{
373373
_dropbox.AddException(ex);
374-
throw;
375374
}
376375

377376
if (messageTask.IsCompleted)
378377
{
379-
return _dropbox.RemoveMessage(responseTo);
378+
return _dropbox.RemoveMessage(responseTo); // also propagates exception if any
380379
}
381380

382381
cancellationToken.ThrowIfCancellationRequested();
@@ -428,7 +427,7 @@ private async Task<IByteBuffer> ReceiveBufferAsync(int responseTo, CancellationT
428427
await Task.WhenAny(messageTask, receiveLockRequest.Task).ConfigureAwait(false);
429428
if (messageTask.IsCompleted)
430429
{
431-
return _dropbox.RemoveMessage(responseTo);
430+
return _dropbox.RemoveMessage(responseTo); // also propagates exception if any
432431
}
433432

434433
receiveLockRequest.Task.GetAwaiter().GetResult(); // propagate exceptions
@@ -442,12 +441,11 @@ private async Task<IByteBuffer> ReceiveBufferAsync(int responseTo, CancellationT
442441
catch (Exception ex)
443442
{
444443
_dropbox.AddException(ex);
445-
throw;
446444
}
447445

448446
if (messageTask.IsCompleted)
449447
{
450-
return _dropbox.RemoveMessage(responseTo);
448+
return _dropbox.RemoveMessage(responseTo); // also propagates exception if any
451449
}
452450

453451
cancellationToken.ThrowIfCancellationRequested();

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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,66 @@ public void ReceiveMessage_should_handle_out_of_order_replies(
468468
}
469469
}
470470

471+
[Theory]
472+
[ParameterAttributeData]
473+
public void ReceiveMessage_should_not_produce_unobserved_task_exceptions_on_fail(
474+
[Values(false, true)] bool async)
475+
{
476+
var unobservedTaskExceptionRaised = false;
477+
var mockStream = new Mock<Stream>();
478+
EventHandler<UnobservedTaskExceptionEventArgs> eventHandler = (s, args) =>
479+
{
480+
unobservedTaskExceptionRaised = true;
481+
args.SetObserved();
482+
};
483+
484+
try
485+
{
486+
TaskScheduler.UnobservedTaskException += eventHandler;
487+
var encoderSelector = new ReplyMessageEncoderSelector<BsonDocument>(BsonDocumentSerializer.Instance);
488+
489+
_mockStreamFactory
490+
.Setup(f => f.CreateStream(_endPoint, CancellationToken.None))
491+
.Returns(mockStream.Object);
492+
493+
if (async)
494+
{
495+
mockStream
496+
.Setup(s => s.ReadAsync(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<CancellationToken>()))
497+
.Throws(new SocketException());
498+
}
499+
else
500+
{
501+
mockStream
502+
.Setup(s => s.Read(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>()))
503+
.Throws(new SocketException());
504+
}
505+
506+
_subject.Open(CancellationToken.None);
507+
508+
Exception exception;
509+
if (async)
510+
{
511+
exception = Record.Exception(() => _subject.ReceiveMessageAsync(1, encoderSelector, _messageEncoderSettings, CancellationToken.None).GetAwaiter().GetResult());
512+
}
513+
else
514+
{
515+
exception = Record.Exception(() => _subject.ReceiveMessage(1, encoderSelector, _messageEncoderSettings, CancellationToken.None));
516+
}
517+
exception.Should().BeOfType<MongoConnectionException>();
518+
519+
GC.Collect(); // Collects the unobserved tasks
520+
GC.WaitForPendingFinalizers(); // Assures finilizers are executed
521+
522+
unobservedTaskExceptionRaised.Should().BeFalse();
523+
}
524+
finally
525+
{
526+
TaskScheduler.UnobservedTaskException -= eventHandler;
527+
mockStream.Object?.Dispose();
528+
}
529+
}
530+
471531
[Theory]
472532
[ParameterAttributeData]
473533
public void ReceiveMessage_should_throw_network_exception_to_all_awaiters(

0 commit comments

Comments
 (0)