// 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);
                }
            }
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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
                }
            }
        }