// methods public void Initialize() { if (_state.TryChange(State.Initial, State.Open)) { if (_listener != null) { _listener.ServerBeforeOpening(_serverId, _settings); } var stopwatch = Stopwatch.StartNew(); _connectionPool.Initialize(); var metronome = new Metronome(_settings.HeartbeatInterval); AsyncBackgroundTask.Start( HeartbeatAsync, ct => { var newDelay = new InterruptibleDelay(metronome.GetNextTickDelay(), ct); Interlocked.Exchange(ref _heartbeatDelay, newDelay); return(newDelay.Task); }, _heartbeatCancellationTokenSource.Token) .HandleUnobservedException(ex => { }); // TODO: do we need to do anything here? stopwatch.Stop(); if (_listener != null) { _listener.ServerAfterOpening(_serverId, _settings, stopwatch.Elapsed); } } }
public void GetNextTickDelay_should_be_infinite_if_period_is_infinite() { var period = Timeout.InfiniteTimeSpan; var subject = new Metronome(period); subject.GetNextTickDelay().Should().Be(Timeout.InfiniteTimeSpan); }
public void GetNextTickDelay_should_be_threeQuarterPeriod_when_oneQuarterPeriod_past_the_last_tick() { var now = _clock.UtcNow; _clock.UtcNow = _clock.UtcNow.Add(_quarterPeriod); _subject.GetNextTickDelay().Should().Be(_threeQuarterPeriod); _subject.NextTick.Should().Be(now + _period); }
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 } } }