private void PublishDiff(MembershipState oldState, MembershipState newState, Action <object> pub) { foreach (var @event in ClusterEvent.DiffMemberEvents(oldState, newState)) { pub(@event); } foreach (var @event in ClusterEvent.DiffUnreachable(oldState, newState)) { pub(@event); } foreach (var @event in ClusterEvent.DiffReachable(oldState, newState)) { pub(@event); } foreach (var @event in ClusterEvent.DiffLeader(oldState, newState)) { pub(@event); } foreach (var @event in ClusterEvent.DiffRolesLeader(oldState, newState)) { pub(@event); } // publish internal SeenState for testing purposes foreach (var @event in ClusterEvent.DiffSeen(oldState, newState)) { pub(@event); } foreach (var @event in ClusterEvent.DiffReachability(oldState, newState)) { pub(@event); } }
/// <summary> /// Compares two <see cref="Gossip"/> instances and uses them to publish the appropriate <see cref="IMemberEvent"/> /// for any given change to the membership of the current cluster. /// </summary> /// <param name="oldState">The previous gossip instance.</param> /// <param name="newState">The new gossip instance.</param> /// <returns>A possibly empty set of membership events to be published to all subscribers.</returns> internal static ImmutableList <IMemberEvent> DiffMemberEvents(MembershipState oldState, MembershipState newState) { if (ReferenceEquals(newState, oldState)) { return(ImmutableList <IMemberEvent> .Empty); } var newMembers = newState.Members.Except(oldState.Members); var membersGroupedByAddress = newState.Members .Concat(oldState.Members) .GroupBy(m => m.UniqueAddress); var changedMembers = membersGroupedByAddress .Where(g => g.Count() == 2 && (g.First().Status != g.Skip(1).First().Status || g.First().UpNumber != g.Skip(1).First().UpNumber)) .Select(g => g.First()); var memberEvents = CollectMemberEvents(newMembers.Union(changedMembers)); var removedMembers = oldState.Members.Except(newState.Members); var removedEvents = removedMembers.Select(m => new MemberRemoved(m.Copy(status: MemberStatus.Removed), m.Status)); return(memberEvents.Concat(removedEvents).ToImmutableList()); }
private void PublishChanges(MembershipState newState) { var oldState = _membershipState; // keep the latest state to be sent to new subscribers _membershipState = newState; PublishDiff(oldState, newState, Publish); }
/// <summary> /// INTERNAL API /// </summary> internal static ImmutableList <ReachabilityChanged> DiffReachability(MembershipState oldState, MembershipState newState) { if (newState.Overview.Reachability.Equals(oldState.Overview.Reachability)) { return(ImmutableList <ReachabilityChanged> .Empty); } return(ImmutableList.Create(new ReachabilityChanged(newState.Overview.Reachability))); }
/// <summary> /// INTERNAL API /// </summary> internal static ImmutableList <LeaderChanged> DiffLeader(MembershipState oldState, MembershipState newState) { var newLeader = newState.Leader; if (newLeader == oldState.Leader) { return(ImmutableList <LeaderChanged> .Empty); } return(ImmutableList.Create(new LeaderChanged(newLeader?.Address))); }
private static IEnumerable <RoleLeaderChanged> InternalDiffRolesLeader(MembershipState oldState, MembershipState newState) { foreach (var role in oldState.LatestGossip.AllRoles.Union(newState.LatestGossip.AllRoles)) { var newLeader = newState.RoleLeader(role); if (newLeader != oldState.RoleLeader(role)) { yield return(new RoleLeaderChanged(role, newLeader?.Address)); } } }
/// <summary> /// Default constructor for ClusterDomainEventPublisher. /// </summary> public ClusterDomainEventPublisher() { _eventStream = Context.System.EventStream; _membershipState = _emptyMembershipState; Receive <InternalClusterAction.PublishChanges>(p => PublishChanges(p.NewState)); Receive <ClusterEvent.CurrentInternalStats>(currentStats => PublishInternalStats(currentStats)); Receive <InternalClusterAction.SendCurrentClusterState>(receiver => SendCurrentClusterState(receiver.Receiver)); Receive <InternalClusterAction.Subscribe>(sub => Subscribe(sub.Subscriber, sub.InitialStateMode, sub.To)); Receive <InternalClusterAction.Unsubscribe>(unsub => Unsubscribe(unsub.Subscriber, unsub.To)); Receive <InternalClusterAction.PublishEvent>(evt => Publish(evt)); }
/// <summary> /// INTERNAL API /// </summary> internal static ImmutableList <ReachableMember> DiffReachable(MembershipState oldState, MembershipState newState) { if (ReferenceEquals(newState, oldState)) { return(ImmutableList <ReachableMember> .Empty); } return(oldState.Overview.Reachability.AllUnreachable .Where(node => newState.LatestGossip.HasMember(node) && newState.Overview.Reachability.IsReachable(node) && !node.Equals(newState.SelfUniqueAddress)) .Select(node => new ReachableMember(newState.LatestGossip.GetMember(node))) .ToImmutableList()); }
/// <summary> /// INTERNAL API /// </summary> internal static ImmutableList <UnreachableMember> DiffUnreachable(MembershipState oldState, MembershipState newState) { if (ReferenceEquals(newState, oldState)) { return(ImmutableList <UnreachableMember> .Empty); } var oldUnreachableNodes = oldState.Overview.Reachability.AllUnreachableOrTerminated; return(newState.Overview.Reachability.AllUnreachableOrTerminated .Where(node => !oldUnreachableNodes.Contains(node) && !node.Equals(newState.SelfUniqueAddress)) .Select(node => new UnreachableMember(newState.LatestGossip.GetMember(node))) .ToImmutableList()); }
/// <summary> /// INTERNAL API /// </summary> internal static ImmutableList <SeenChanged> DiffSeen(MembershipState oldState, MembershipState newState) { if (ReferenceEquals(newState, oldState)) { return(ImmutableList <SeenChanged> .Empty); } var newConvergence = newState.Convergence(ImmutableHashSet <UniqueAddress> .Empty); var newSeenBy = newState.LatestGossip.SeenBy; if (!newConvergence.Equals(oldState.Convergence(ImmutableHashSet <UniqueAddress> .Empty)) || !newSeenBy.SequenceEqual(oldState.LatestGossip.SeenBy)) { return(ImmutableList.Create(new SeenChanged(newConvergence, newSeenBy.Select(s => s.Address).ToImmutableHashSet()))); } return(ImmutableList <SeenChanged> .Empty); }
private void ClearState() { _membershipState = _emptyMembershipState; }
/// <summary> /// INTERNAL API /// </summary> internal static ImmutableHashSet <RoleLeaderChanged> DiffRolesLeader(MembershipState oldState, MembershipState newState) { return(InternalDiffRolesLeader(oldState, newState).ToImmutableHashSet()); }