public Task RegisterMemberAsync(
            Cluster cluster, string clusterName, string host, int port, string[] kinds,
            IMemberStatusValue statusValue, IMemberStatusValueSerializer serializer
            )
        {
            var props = Props.FromFunc(
                ctx =>
            {
                if (ctx.Message is GetKinds && ctx.Sender != null)
                {
                    ctx.Respond(new GetKindsResponse {
                        Kinds = { _kinds }
                    });
                }

                return(Actor.Done);
            }
                );

            cluster.Remote.Serialization.RegisterFileDescriptor(ProtosReflection.Descriptor);

            cluster.Remote.RegisterKnownKind(KindsResponder, props);

            _kinds    = kinds;
            _okStatus = serializer.Deserialize("Ok!");
            _koStatus = serializer.Deserialize("Ko!");

            _isServer = host == _serverHost && port == _serverPort;

            return(Actor.Done);
        }
コード例 #2
0
        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));
            }