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); }
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)); }