示例#1
0
        private async Task NotifyStatusesAsync()
        {
            var statuses = await _client.Health.Service(_clusterName, null, false, new QueryOptions
            {
                WaitIndex = _index,
                WaitTime  = _blockingWaitTime
            });

            _index = statuses.LastIndex;
            var kvKey = _clusterName + "/";
            var kv    = await _client.KV.List(kvKey);

            var memberIds = new Dictionary <string, long>();

            foreach (var v in kv.Response)
            {
                //Read the ID per member.
                //The value is used to see if an existing node have changed its ID over time
                //meaning that it has Re-joined the cluster.
                memberIds[v.Key] = BitConverter.ToInt64(v.Value, 0);
            }
            var memberStatuses =
                from v in statuses.Response
                let memberIdKey = $"{_clusterName}/{v.Service.Address}:{v.Service.Port}"
                                  let memberId = memberIds[memberIdKey]
                                                 let passing = Equals(v.Checks[1].Status, HealthStatus.Passing)
                                                               select new MemberStatus(memberId, v.Service.Address, v.Service.Port, v.Service.Tags, passing);
            var res = new ClusterTopologyEvent(memberStatuses);

            Actor.EventStream.Publish(res);
        }
示例#2
0
        private void NotifyStatuses()
        {
            MemberStatus status = null;

            if (_isServer)
            {
                status = new MemberStatus(_serverAddress, _serverHost, _serverPort, _kinds, true, _okStatus);
            }
            else
            {
                var responder = Remote.Remote.SpawnNamedAsync(_serverAddress, KINDS_RESPONDER, KINDS_RESPONDER, _timeout).Result;
                if (responder.Pid != null)
                {
                    try
                    {
                        var response = RootContext.Empty.RequestAsync <GetKindsResponse>(responder.Pid, new GetKinds(), _timeout).Result;
                        status = new MemberStatus(_serverAddress, _serverHost, _serverPort, response.Kinds, true, _okStatus);
                    }
                    catch (Exception ex) when(ex is TimeoutException || ex.InnerException is TimeoutException)
                    {
                        status = new MemberStatus(_serverAddress, _serverHost, _serverPort, new string[0], true, _koStatus);
                    }
                }
                else
                {
                    status = new MemberStatus(_serverAddress, _serverHost, _serverPort, new string[0], false, _koStatus);
                }
            }

            var @event = new ClusterTopologyEvent(new[] { status });

            Actor.EventStream.Publish(@event);

            Thread.Sleep(TimeSpan.FromMinutes(1));
        }
        private async Task NotifyStatuses(ulong index, PID self)
        {
            var statuses = await _client.Health.Service(
                _clusterName, null, false, new QueryOptions
            {
                WaitIndex = index,
                WaitTime  = _options.BlockingWaitTime
            }
                );

            Logger.LogDebug("Consul response: {@Response}", (object)statuses.Response);

            var reportedServices =
                statuses.Response
                .Select(
                    x => new
            {
                Status = new MemberStatus(
                    x.Service.ID, x.Service.Address, x.Service.Port, x.Service.Tags,
                    x.Checks.All(c => c.Status.Status != "critical"),
                    _statusValueSerializer.Deserialize(x.Service.Meta["StatusValue"])
                    ),
                DeregisterInterval = Parse(x.Service.Meta["DeregisterInterval"])
            }
                    )
                .ToList();

            var memberStatuses = reportedServices.Select(x => x.Status).ToList();

            // Update Tags (kinds) for this member
            _kinds = memberStatuses.FirstOrDefault(x => x.Address == _address && x.Port == _port)?.Kinds.ToArray();

            // Consul has the minimal deregister interval of 1 minute. Our default interval is 30 seconds, but Consul won't support it.
            // Therefore, we check if there are any members that fails on TTL check is recorded and when the specified interval expires,
            OverrideConsulDeregisterInterval();

            var res = new ClusterTopologyEvent(memberStatuses);

            _system.EventStream.Publish(res);

            _system.Root.Send(self, new CheckStatus {
                Index = statuses.LastIndex
            });

            void OverrideConsulDeregisterInterval()
            {
                var deadMembers = reportedServices
                                  .Where(x => !x.Status.Alive && x.DeregisterInterval != default)
                                  .Select(x => new DeadMember(x.Status.MemberId, DateTimeOffset.UtcNow, x.DeregisterInterval))
                                  .ToList();

                if (deadMembers.Count == 0)
                {
                    return;
                }

                // Remove members that have recovered
                _knownDeadMembers.RemoveAll(x => !deadMembers.Contains(x));

                // Find newly discovered dead members
                var newDeadMembers = deadMembers.Except(_knownDeadMembers);

                // Add newly discovered dead members to the list of known dead members.
                // Cannot use Concat/Distinct since we must keep the timestamp.
                _knownDeadMembers.AddRange(newDeadMembers);

                var reportMissing = _knownDeadMembers
                                    .Where(x => DateTimeOffset.UtcNow > x.FoundDeadAt + x.DeregisterInterval)
                                    .Select(x => x.MemberId)
                                    .ToList();

                if (reportMissing.Count > 0)
                {
                    Logger.LogInformation("Members to be excluded {@Dead}", reportMissing);
                }

                memberStatuses.RemoveAll(x => reportMissing.Contains(x.MemberId));
            }