private void HearthBeatLoop()
 {
     while (_live)
     {
         foreach (var clientConnection in _addresses.Values)
         {
             var request = ClientPingCodec.EncodeRequest();
             var task    = ((ClientInvocationService)_client.GetInvocationService()).InvokeOnConnection(request, clientConnection);
             Logger.Finest("Sending heartbeat request to " + clientConnection.GetAddress());
             try
             {
                 var response = ThreadUtil.GetResult(task, _heartBeatTimeout);
                 var result   = ClientPingCodec.DecodeResponse(response);
                 Logger.Finest("Got heartbeat response from " + clientConnection.GetAddress());
             }
             catch (Exception e)
             {
                 Logger.Warning(string.Format("Error getting heartbeat from {0}: {1}", clientConnection.GetAddress(), e));
                 var connection = clientConnection;
                 FireHeartBeatEvent((listener) => listener.HeartBeatStopped(connection));
             }
         }
         try
         {
             Thread.Sleep(_heartBeatInterval);
         }
         catch (Exception)
         {
             break;
         }
     }
 }
예제 #2
0
        // runs once on a connection to a member
        private async Task RunAsync(MemberConnection connection, DateTime now, CancellationToken cancellationToken)
        {
            // must ensure that timeout > interval ?!

            var readElapsed  = now - connection.LastReadTime;
            var writeElapsed = now - connection.LastWriteTime;

            HConsole.WriteLine(this, $"Heartbeat on {connection.Id.ToShortString()}, written {(long)(now - connection.LastWriteTime).TotalMilliseconds}ms ago, read {(long)(now - connection.LastReadTime).TotalMilliseconds}ms ago");

            // make sure we read from the client at least every 'timeout',
            // which is greater than the interval, so we *should* have
            // read from the last ping, if nothing else, so no read means
            // that the client not responsive - terminate it

            if (readElapsed > _timeout && writeElapsed < _period)
            {
                _logger.LogWarning("Heartbeat timeout for connection {ConnectionId}.", connection.Id);
                if (connection.Active)
                {
                    await connection.TerminateAsync().CfAwait();                    // does not throw;
                }
                return;
            }

            // make sure we write to the client at least every 'interval',
            // this should trigger a read when we receive the response
            if (writeElapsed > _period)
            {
                _logger.LogDebug("Ping client {ClientId}", connection.Id);

                var requestMessage = ClientPingCodec.EncodeRequest();

                try
                {
                    // ping should complete within the default invocation timeout
                    var responseMessage = await _clusterMessaging
                                          .SendToMemberAsync(requestMessage, connection, cancellationToken)
                                          .CfAwait();

                    // just to be sure everything is ok
                    _ = ClientPingCodec.DecodeResponse(responseMessage);
                }
                catch (TaskTimeoutException)
                {
                    _logger.LogWarning("Heartbeat ping timeout for connection {ConnectionId}.", connection.Id);
                    if (connection.Active)
                    {
                        await connection.TerminateAsync().CfAwait();                    // does not throw;
                    }
                }
                catch (Exception e)
                {
                    // unexpected
                    _logger.LogWarning(e, "Heartbeat has thrown an exception.");
                }
            }
        }
        // runs once on a connection to a member
        private async Task RunAsync(MemberConnection connection, DateTime now, CancellationToken cancellationToken)
        {
            // must ensure that timeout > interval ?!

            // make sure we read from the client at least every 'timeout',
            // which is greater than the interval, so we *should* have
            // read from the last ping, if nothing else, so no read means
            // that the client not responsive - terminate it
            if (now - connection.LastReadTime > _timeout)
            {
                await TerminateConnection(connection).CAF();

                return;
            }

            // make sure we write to the client at least every 'interval',
            // this should trigger a read when we receive the response
            if (now - connection.LastWriteTime > _period)
            {
                _logger.LogDebug("Ping client {ClientId}", connection.Id);

                var requestMessage = ClientPingCodec.EncodeRequest();
                var cancellation   = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

                try
                {
                    // cannot wait forever on a ping
                    var responseMessage = await _clusterMessaging
                                          .SendToMemberAsync(requestMessage, connection, cancellation.Token)
                                          .TimeoutAfter(_pingTimeout, cancellation, true)
                                          .CAF();

                    // just to be sure everything is ok
                    _ = ClientPingCodec.DecodeResponse(responseMessage);
                }
                catch (TaskTimeoutException)
                {
                    await TerminateConnection(connection).CAF();
                }
                catch (Exception e)
                {
                    // unexpected
                    _logger.LogWarning(e, "Heartbeat has thrown an exception.");
                }
                finally
                {
                    // if .SendToClientAsync() throws before awaiting, .TimeoutAfter() is never invoked
                    // and therefore cannot dispose the cancellation = better take care of it
                    cancellation.Dispose();
                }
            }
        }
예제 #4
0
        // runs once on a connection to a member
        private async Task RunAsync(MemberConnection connection, DateTime now, CancellationToken cancellationToken)
        {
            var readElapsed  = now - connection.LastReadTime;
            var writeElapsed = now - connection.LastWriteTime;

            HConsole.WriteLine(this, $"Heartbeat {_clusterState.ClientName} on {connection.Id.ToShortString()} to {connection.MemberId.ToShortString()} at {connection.Address}, " +
                               $"written {(int)writeElapsed.TotalSeconds}s ago, " +
                               $"read {(int)readElapsed.TotalSeconds}s ago");

            // make sure we read from the client at least every 'timeout',
            // which is greater than the interval, so we *should* have
            // read from the last ping, if nothing else, so no read means
            // that the client not responsive - terminate it

            if (readElapsed > _timeout && writeElapsed < _period)
            {
                _logger.LogWarning("Heartbeat timeout for connection {ConnectionId}, terminating.", connection.Id.ToShortString());
                if (connection.Active)
                {
                    _terminateConnections.Add(connection);
                }
                return;
            }

            // make sure we write to the client at least every 'period',
            // this should trigger a read when we receive the response
            if (writeElapsed > _period)
            {
                _logger.LogDebug("Ping client {ClientId}", connection.Id.ToShortString());

                var requestMessage = ClientPingCodec.EncodeRequest();

                try
                {
                    // ping should complete within the default invocation timeout
                    var responseMessage = await _clusterMessaging
                                          .SendToMemberAsync(requestMessage, connection, cancellationToken)
                                          .CfAwait();

                    // just to be sure everything is ok
                    _ = ClientPingCodec.DecodeResponse(responseMessage);
                }
                catch (ClientOfflineException)
                {
                    // down
                }
                catch (TaskTimeoutException)
                {
                    _logger.LogWarning("Heartbeat ping timeout for connection {ConnectionId}, terminating.", connection.Id.ToShortString());
                    if (connection.Active)
                    {
                        _terminateConnections.Add(connection);
                    }
                }
                catch (Exception e)
                {
                    // unexpected
                    _logger.LogWarning(e, "Heartbeat has thrown an exception, but will continue.");
                }
            }
        }