public void Dispose_can_be_called_multiple_times() { var subject = new HeartbeatDelay(TimeSpan.FromHours(10), TimeSpan.FromMilliseconds(1)); subject.Dispose(); subject.Dispose(); }
private async Task MonitorServerAsync() { var metronome = new Metronome(_settings.HeartbeatInterval); var heartbeatCancellationToken = _heartbeatCancellationTokenSource.Token; while (!heartbeatCancellationToken.IsCancellationRequested) { try { await HeartbeatAsync(heartbeatCancellationToken).ConfigureAwait(false); var newHeartbeatDelay = new HeartbeatDelay(metronome.GetNextTickDelay(), __minHeartbeatInterval); var oldHeartbeatDelay = Interlocked.Exchange(ref _heartbeatDelay, newHeartbeatDelay); if (oldHeartbeatDelay != null) { oldHeartbeatDelay.Dispose(); } await newHeartbeatDelay.Task.ConfigureAwait(false); } catch { // ignore these exceptions } } }
// methods public void Initialize() { if (_state.TryChange(State.Initial, State.Open)) { if (_listener != null) { _listener.ServerBeforeOpening(new ServerBeforeOpeningEvent(_serverId, _settings)); } var stopwatch = Stopwatch.StartNew(); _connectionPool.Initialize(); var metronome = new Metronome(_settings.HeartbeatInterval); AsyncBackgroundTask.Start( HeartbeatAsync, ct => { var newHeartbeatDelay = new HeartbeatDelay(metronome.GetNextTickDelay(), __minHeartbeatInterval); var oldHeartbeatDelay = Interlocked.Exchange(ref _heartbeatDelay, newHeartbeatDelay); if (oldHeartbeatDelay != null) { oldHeartbeatDelay.Dispose(); } return(newHeartbeatDelay.Task); }, _heartbeatCancellationTokenSource.Token) .HandleUnobservedException(ex => { }); // TODO: do we need to do anything here? stopwatch.Stop(); if (_listener != null) { _listener.ServerAfterOpening(new ServerAfterOpeningEvent(_serverId, _settings, stopwatch.Elapsed)); } } }
public void Task_should_complete_when_early_heartbeat_is_requested() { var subject = new HeartbeatDelay(TimeSpan.FromHours(10), TimeSpan.FromMilliseconds(1)); subject.RequestHeartbeat(); subject.Task.Wait(TimeSpan.FromSeconds(1)).Should().BeTrue(); }
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)); subject.RequestHeartbeat(); SpinWait.SpinUntil(() => subject.Task.Status != TaskStatus.WaitingForActivation, TimeSpan.FromMilliseconds(1500)).Should().BeFalse(); Thread.Sleep(TimeSpan.FromMilliseconds(700)); subject.Task.Status.Should().Be(TaskStatus.RanToCompletion); }
public void RequestHeartbeat_should_respect_to_minHeartbeatInterval([Values(10, -1)] int heartbeatIntervalInMinutes) { var heartbeatInterval = heartbeatIntervalInMinutes == -1 ? Timeout.InfiniteTimeSpan : TimeSpan.FromMinutes(heartbeatIntervalInMinutes); 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(); stopwatch.Elapsed.Should().BeGreaterOrEqualTo(minHeartbeatInterval - TimeSpan.FromMilliseconds(15)); }
public void Task_should_complete_when_heartbeatInterval_has_expired() { var subject = new HeartbeatDelay(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(1)); subject.Task.Wait(TimeSpan.FromSeconds(1)).Should().BeTrue(); }
private async Task MonitorServerAsync() { var metronome = new Metronome(_interval); var heartbeatCancellationToken = _cancellationTokenSource.Token; while (!heartbeatCancellationToken.IsCancellationRequested) { try { await HeartbeatAsync(heartbeatCancellationToken).ConfigureAwait(false); var newHeartbeatDelay = new HeartbeatDelay(metronome.GetNextTickDelay(), __minHeartbeatInterval); var oldHeartbeatDelay = Interlocked.Exchange(ref _heartbeatDelay, newHeartbeatDelay); if (oldHeartbeatDelay != null) { oldHeartbeatDelay.Dispose(); } await newHeartbeatDelay.Task.ConfigureAwait(false); } catch { // ignore these exceptions } } }
private async Task MonitorServerAsync() { var metronome = new Metronome(_heartbeatInterval); var heartbeatCancellationToken = _cancellationTokenSource.Token; while (!heartbeatCancellationToken.IsCancellationRequested) { try { try { await HeartbeatAsync(heartbeatCancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) when(heartbeatCancellationToken.IsCancellationRequested) { // ignore OperationCanceledException when heartbeat cancellation is requested } catch (Exception unexpectedException) { // if we catch an exception here it's because of a bug in the driver (but we need to defend ourselves against that) var handler = _sdamInformationEventHandler; if (handler != null) { try { handler.Invoke(new SdamInformationEvent(() => string.Format( "Unexpected exception in ServerMonitor.MonitorServerAsync: {0}", unexpectedException.ToString()))); } catch { // ignore any exceptions thrown by the handler (note: event handlers aren't supposed to throw exceptions) } } // since an unexpected exception was thrown set the server description to Unknown (with the unexpected exception) try { // keep this code as simple as possible to keep the surface area with any remaining possible bugs as small as possible var newDescription = _baseDescription.WithHeartbeatException(unexpectedException); // not With in case the bug is in With SetDescription(newDescription); // not SetDescriptionIfChanged in case the bug is in SetDescriptionIfChanged } catch { // if even the simple code in the try throws just give up (at least we've raised the unexpected exception via an SdamInformationEvent) } } var newHeartbeatDelay = new HeartbeatDelay(metronome.GetNextTickDelay(), __minHeartbeatInterval); var oldHeartbeatDelay = Interlocked.Exchange(ref _heartbeatDelay, newHeartbeatDelay); if (oldHeartbeatDelay != null) { oldHeartbeatDelay.Dispose(); } await newHeartbeatDelay.Task.ConfigureAwait(false); } catch { // ignore these exceptions } } }
private async Task MonitorServerAsync() { await Task.Yield(); // return control immediately var metronome = new Metronome(_serverMonitorSettings.HeartbeatInterval); var monitorCancellationToken = _monitorCancellationTokenSource.Token; while (!monitorCancellationToken.IsCancellationRequested) { try { CancellationToken cachedHeartbeatCancellationToken; lock (_lock) { cachedHeartbeatCancellationToken = _heartbeatCancellationTokenSource.Token; // we want to cache the current cancellation token in case the source changes } try { await HeartbeatAsync(cachedHeartbeatCancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) when(cachedHeartbeatCancellationToken.IsCancellationRequested) { // ignore OperationCanceledException when heartbeat cancellation is requested } catch (Exception unexpectedException) { // if we catch an exception here it's because of a bug in the driver (but we need to defend ourselves against that) var handler = _sdamInformationEventHandler; if (handler != null) { try { handler.Invoke(new SdamInformationEvent(() => string.Format( "Unexpected exception in ServerMonitor.MonitorServerAsync: {0}", unexpectedException.ToString()))); } catch { // ignore any exceptions thrown by the handler (note: event handlers aren't supposed to throw exceptions) } } // since an unexpected exception was thrown set the server description to Unknown (with the unexpected exception) try { // keep this code as simple as possible to keep the surface area with any remaining possible bugs as small as possible var newDescription = _baseDescription.WithHeartbeatException(unexpectedException); // not With in case the bug is in With SetDescription(newDescription); // not SetDescriptionIfChanged in case the bug is in SetDescriptionIfChanged } catch { // if even the simple code in the try throws just give up (at least we've raised the unexpected exception via an SdamInformationEvent) } } HeartbeatDelay newHeartbeatDelay; lock (_lock) { newHeartbeatDelay = new HeartbeatDelay(metronome.GetNextTickDelay(), _serverMonitorSettings.MinHeartbeatInterval); if (_heartbeatDelay != null) { _heartbeatDelay.Dispose(); } _heartbeatDelay = newHeartbeatDelay; } await newHeartbeatDelay.Task.ConfigureAwait(false); // corresponds to wait method in spec } catch { // ignore these exceptions } } }