Skip to content

Commit

Permalink
CSHARP-3182: Getting timeout error when using driver in WinForms .net…
Browse files Browse the repository at this point in the history
… core 3.1 project.
  • Loading branch information
DmitryLukyanov authored and rstam committed Aug 21, 2020
1 parent 693ac5b commit f09dbbc
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 9 deletions.
2 changes: 0 additions & 2 deletions src/MongoDB.Driver.Core/Core/Servers/RoundTripTimeMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,6 @@ public void Dispose()

public async Task RunAsync()
{
await Task.Yield(); // return control immediately

while (!_cancellationToken.IsCancellationRequested)
{
try
Expand Down
11 changes: 8 additions & 3 deletions src/MongoDB.Driver.Core/Core/Servers/ServerMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,14 @@ public void Initialize()
{
if (_state.TryChange(State.Initial, State.Open))
{
_ = MonitorServerAsync().ConfigureAwait(false);
// the call to Task.Factory.StartNew is not normally recommended or necessary
// we are using it temporarily to work around a race condition in some of our tests
// the issue is that we set up some mocked async methods to return results immediately synchronously
// which results in the MonitorServerAsync method making more progress synchronously than the test expected
// by using Task.Factory.StartNew we introduce a short delay before the MonitorServerAsync Task starts executing
// the delay is whatever time it takes for the new Task to be activated and scheduled
// and the delay is usually long enough for the test to get past the race condition (though not guaranteed)
_ = Task.Factory.StartNew(() => _ = MonitorServerAsync().ConfigureAwait(false)).ConfigureAwait(false);
_ = _roundTripTimeMonitor.RunAsync().ConfigureAwait(false);
}
}
Expand Down Expand Up @@ -189,8 +196,6 @@ private async Task<IConnection> InitializeConnectionAsync(CancellationToken canc

private async Task MonitorServerAsync()
{
await Task.Yield(); // return control immediately

var metronome = new Metronome(_serverMonitorSettings.HeartbeatInterval);
var monitorCancellationToken = _monitorCancellationTokenSource.Token;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
Expand All @@ -38,13 +39,20 @@ public void Dispose_can_be_called_multiple_times()
public void RequestHeartbeat_should_respect_to_minHeartbeatInterval([Values(10, -1)]int heartbeatIntervalInMinutes)
{
var heartbeatInterval = heartbeatIntervalInMinutes == -1 ? Timeout.InfiniteTimeSpan : TimeSpan.FromMinutes(heartbeatIntervalInMinutes);
var subject = new HeartbeatDelay(heartbeatInterval, TimeSpan.FromSeconds(2));
var minHeartbeatInterval = TimeSpan.FromSeconds(2);

var stopwatch = Stopwatch.StartNew();
var subject = new HeartbeatDelay(heartbeatInterval, minHeartbeatInterval);
subject.RequestHeartbeat();
var timeout = TimeSpan.FromMinutes(1);
var result = Task.WaitAny(subject.Task, Task.Delay(timeout));
if (result != 0)
{
throw new Exception($"The test timeout {timeout} is exceeded.");
}
stopwatch.Stop();

SpinWait.SpinUntil(() => subject.Task.Status != TaskStatus.WaitingForActivation, TimeSpan.FromMilliseconds(1500)).Should().BeFalse();
Thread.Sleep(TimeSpan.FromMilliseconds(700));
subject.Task.Status.Should().Be(TaskStatus.RanToCompletion);
stopwatch.Elapsed.Should().BeGreaterOrEqualTo(minHeartbeatInterval - TimeSpan.FromMilliseconds(15));
}

[Fact]
Expand Down

0 comments on commit f09dbbc

Please sign in to comment.