Esempio n. 1
0
        public void ShouldDownAllMembersWhenNotEnoughNodes()
        {
            string refereeAddress = "akka.tcp://system@localhost:33333";

            var referee = TestUtils.CreateMember(MemberStatus.Up, Address.Parse(refereeAddress));

            var members =
                TestUtils.CreateMembers(MemberStatus.Up)
                .Take(4)
                .Concat(new List <Member> {
                referee
            })
                .ToImmutableSortedSet();

            var unreachable =
                members.Where(m => m != referee)
                .Take(2)
                .ToImmutableHashSet();

            var state    = new CurrentClusterState().Copy(members, unreachable);
            var strategy = new KeepRefereeDowningStrategy(refereeAddress, downAllIfLessThanNodes: 4);

            var victims = strategy.GetVictims(state);

            victims.ToImmutableHashSet().SetEquals(members)
            .Should().BeTrue("We have 3 available members, which is less than downAllIfLessThanNodes 4, so down all members");
        }
Esempio n. 2
0
        public IEnumerable <Member> GetVictims(CurrentClusterState clusterState)
        {
            var oldest        = clusterState.GetMembers(Role).SortByAge().FirstOrDefault();
            var available     = clusterState.GetAvailableMembers(Role);
            var haveOldest    = oldest != null && available.Contains(oldest);
            var oldestIsAlone =
                (haveOldest && available.Count == 1) ||
                (!haveOldest && available.Count == clusterState.GetMembers(Role).Count - 1);

            if (oldest == null)
            {
                return(clusterState.GetUnreachableMembers());
            }

            if (oldestIsAlone && DownIfAlone)
            {
                return new List <Member> {
                           oldest
                }
            }
            ;

            return(haveOldest
                ? clusterState.GetUnreachableMembers()
                : clusterState.GetMembers());
        }
    }
Esempio n. 3
0
        public void ShouldDownMembersInPartitionsWithoutReferee()
        {
            string refereeAddress = "akka.tcp://system@localhost:33333";

            var referee = TestUtils.CreateMember(MemberStatus.Up, Address.Parse(refereeAddress));

            var members =
                TestUtils.CreateMembers(MemberStatus.Up)
                .Take(4)
                .Concat(new List <Member> {
                referee
            })
                .ToImmutableSortedSet();

            var unreachable =
                members.Where(m => m != referee)
                .Take(2)
                .Concat(new List <Member> {
                referee
            })
                .ToImmutableHashSet();

            var state    = new CurrentClusterState().Copy(members, unreachable);
            var strategy = new KeepRefereeDowningStrategy(refereeAddress, downAllIfLessThanNodes: 0);

            var victims = strategy.GetVictims(state);

            victims.ToImmutableHashSet().SetEquals(members)
            .Should().BeTrue("When we don't have the referee, we down all members");
        }
Esempio n. 4
0
        public static ImmutableHashSet <Member> GetMembers(this CurrentClusterState state, string role = null)
        {
            bool ShouldConsider(Member member) => CurrentClusterStateExtensions.ShouldConsider(member, role);

            return(state.Members.Where(ShouldConsider)
                   .ToImmutableHashSet());
        }
Esempio n. 5
0
        /// <summary>
        /// The strategy named keep-majority will down the unreachable nodes if the
        /// current node is in the majority part based on the last known membership information.
        /// Otherwise down the reachable nodes, i.e. the own part. If the parts are of equal size
        /// the part containing the node with the lowest address is kept.
        /// </summary>
        public IEnumerable <Member> GetVictims(CurrentClusterState clusterState)
        {
            var members            = clusterState.GetMembers(Role);
            var unreachableMembers = clusterState.GetUnreachableMembers(Role);
            var availableMembers   = clusterState.GetAvailableMembers(Role);

            int unreachableCount = unreachableMembers.Count;
            int availableCount   = availableMembers.Count;

            if (availableCount == unreachableCount)
            {
                var oldest = clusterState.GetMembers(Role).SortByAge().FirstOrDefault();
                if (oldest != null && availableMembers.Contains(oldest))
                {
                    return(clusterState.GetUnreachableMembers());
                }
                else
                {
                    return(clusterState.GetMembers());
                }
            }

            return(availableCount < unreachableCount
                   //too few available, down our partition (entire members)
                ? clusterState.GetMembers()
                   //enough available, down unreachable
                : clusterState.GetUnreachableMembers());;
        }
Esempio n. 6
0
        public void ShouldNotDownPartitionWithOldestWhenEqualMembers()
        {
            var oldest = TestUtils.CreateMembers(MemberStatus.Up).First();

            //Oldest is in the reachable members
            var members = TestUtils.CreateMembers(MemberStatus.Up)
                          .Take(5)
                          .ToImmutableSortedSet()
                          .Add(oldest);

            var unreachableMembers = members
                                     .Where(m => !m.Equals(oldest))
                                     .Take(3)
                                     .ToImmutableHashSet();

            var clusterState =
                new CurrentClusterState().Copy(members: members, unreachable: unreachableMembers);

            var strategy = new KeepMajorityDowningStrategy();

            var victims = strategy.GetVictims(clusterState).ToList();

            victims.ToImmutableSortedSet().SetEquals(unreachableMembers)
            .Should().BeTrue("Partition with oldest should not be marked for downing");
        }
Esempio n. 7
0
        public void ShouldDownUnreachableMembersInMajorityPartitionsConsideringRole()
        {
            string roleName = "SomeRole";
            var    roles = new string[] { roleName }.ToImmutableHashSet();

            var membersInRole            = TestUtils.CreateMembers(MemberStatus.Up, roles).Take(3).ToList();
            var unreachableMembersInRole = membersInRole.Take(1).ToImmutableHashSet();

            var members = TestUtils.CreateMembers(MemberStatus.Up)
                          .Take(4)
                          .Concat(membersInRole)
                          .ToImmutableSortedSet();

            var clusterState =
                new CurrentClusterState().Copy(members: members, unreachable: unreachableMembersInRole);

            var strategy = new KeepMajorityDowningStrategy(roleName);

            var victims = strategy.GetVictims(clusterState).ToList();

            victims.ToImmutableHashSet().SetEquals(unreachableMembersInRole)
            .Should().BeTrue("Unreachable members in majority should be marked for downing");

            victims.All(v => v.HasRole(roleName))
            .Should().BeTrue("We should only down members in the specified role");
        }
Esempio n. 8
0
        public IEnumerable <Member> GetVictims(CurrentClusterState clusterState)
        {
            bool haveReferee = clusterState.HasAvailableMember(Address);

            return(!haveReferee || clusterState.GetAvailableMembers().Count < DownAllIfLessThanNodes
                ? clusterState.GetMembers()
                : clusterState.GetUnreachableMembers());
        }
Esempio n. 9
0
        public static bool HasAvailableMember(this CurrentClusterState state, Address address)
        {
            var member     = state.Members.FirstOrDefault(m => m.Address.Equals(address)); //cannot use ==
            var unavilable = state.Unreachable.FirstOrDefault(m => m.Address.Equals(address));

            return(member != null && unavilable == null
                ? member.Status == MemberStatus.Up
                : false);
        }
Esempio n. 10
0
        public void NotifyNewCurrentState(CurrentClusterState newState)
        {
            currentState = newState;
            var message = new ClusterStateMessage {
                ClusterState = currentState
            };
            var json = JsonConvert.SerializeObject(message);

            currentStateSubject.OnNext(json);
        }
Esempio n. 11
0
        public void NotifyMemberRemoved(CurrentClusterState newState, Member memberRemoved)
        {
            currentState = newState;
            var message = new MemberRemovedMessage
            {
                ClusterState  = currentState,
                MemberRemoved = memberRemoved
            };
            var json = JsonConvert.SerializeObject(message);

            currentStateSubject.OnNext(json);
        }
Esempio n. 12
0
        public IEnumerable <Member> GetVictims(CurrentClusterState clusterState)
        {
            var members        = clusterState.GetMembers(Role);
            var unreachable    = clusterState.GetUnreachableMembers(Role);
            int availableCount = members.Count - unreachable.Count;

            return(availableCount < QuorumSize
                   //too few available, down our partition
                ? clusterState.GetMembers()
                   //enough available, down unreachable
                : clusterState.GetUnreachableMembers());
        }
Esempio n. 13
0
        public void ShouldNotDownPartitionsWithEnoughMembers()
        {
            var members = TestUtils.CreateMembers(MemberStatus.Up).Take(3).ToImmutableSortedSet();

            var clusterState =
                new CurrentClusterState()
                .Copy(members);

            var strategy = new StaticQuorumDowningStrategy(quorumSize: 3);
            var victims  = strategy.GetVictims(clusterState);

            victims.Count().Should().Be(0, "Partitions with quorum size or greater should not be marked for downing");
        }
Esempio n. 14
0
        public void ShouldDownUnreachablesWhenEnoughAvailableMembers()
        {
            var members            = TestUtils.CreateMembers(MemberStatus.Up).Take(5).ToImmutableSortedSet();
            var unreachableMembers = members.Take(2).ToImmutableHashSet();

            var clusterState =
                new CurrentClusterState()
                .Copy(members: members, unreachable: unreachableMembers);

            var strategy = new StaticQuorumDowningStrategy(quorumSize: 3);
            var victims  = strategy.GetVictims(clusterState).ToList();

            victims.ToImmutableHashSet().SetEquals(unreachableMembers)
            .Should().BeTrue("Partitions with available members >= quorum size should down unreachable members");
        }
Esempio n. 15
0
        public void ShouldDownPartitionsWithTooFewAvailableMembers()
        {
            var members            = TestUtils.CreateMembers(MemberStatus.Up).Take(3).ToImmutableSortedSet();
            var unreachableMembers = members.Take(1).ToImmutableHashSet();

            var clusterState =
                new CurrentClusterState()
                .Copy(members, unreachableMembers);

            var strategy = new StaticQuorumDowningStrategy(quorumSize: 3);
            var victims  = strategy.GetVictims(clusterState);

            victims.ToImmutableHashSet().SetEquals(members)
            .Should().BeTrue("Partitions with fewer available members than the quorum size should be marked for downing");
        }
Esempio n. 16
0
        public void ShouldDownMinorityPartitions()
        {
            var strategy = new KeepMajorityDowningStrategy();

            var members            = TestUtils.CreateMembers(MemberStatus.Up).Take(5).ToImmutableSortedSet();
            var unreachableMembers = members.Take(3).ToImmutableHashSet();

            var clusterState =
                new CurrentClusterState()
                .Copy(members: members, unreachable: unreachableMembers);

            var victims = strategy.GetVictims(clusterState).ToList();

            victims.ToImmutableHashSet().SetEquals(members)
            .Should().BeTrue("Minority partitions should be marked for downing");
        }
Esempio n. 17
0
        public void ShouldNotDownPartitionsWithEnoughMembersInRole()
        {
            string roleName = "SomeRole";
            var    roles = new string[] { roleName }.ToImmutableHashSet();

            var membersInRole = TestUtils.CreateMembers(MemberStatus.Up, roles).Take(3).ToList();
            var members       =
                TestUtils.CreateMembers(MemberStatus.Up)
                .Take(2)
                .Concat(membersInRole)
                .ToImmutableSortedSet();

            var clusterState = new CurrentClusterState().Copy(members);

            var strategy = new StaticQuorumDowningStrategy(quorumSize: 3, role: roleName);
            var victims  = strategy.GetVictims(clusterState);

            victims.Count().Should().Be(0, "Partitions with fewer than the quorum size should be marked for downing");
        }
Esempio n. 18
0
        public void ShouldDownRemoteOldestWhenOldestAndAlone()
        {
            var oldest = TestUtils.CreateMembers(MemberStatus.Up).First();

            var rest = TestUtils.CreateMembers(MemberStatus.Up)
                       .Take(4)
                       .ToImmutableSortedSet();

            var members     = rest.Add(oldest);
            var unreachable = ImmutableHashSet <Member> .Empty.Add(oldest);

            var state    = new CurrentClusterState().Copy(members, unreachable);
            var strategy = new KeepOldestDowningStrategy(downIfAlone: true);

            var victims = strategy.GetVictims(state);

            victims.ToImmutableHashSet().SetEquals(ImmutableHashSet <Member> .Empty.Add(oldest))
            .Should().BeTrue("When downIfAlone=true, we should down the oldest member if its clustered by itself");
        }
Esempio n. 19
0
        public void ShouldDownSelfWhenNotInOldestPartition()
        {
            var oldest = TestUtils.CreateMembers(MemberStatus.Up).First();

            var members = TestUtils.CreateMembers(MemberStatus.Up)
                          .Take(4)
                          .ToImmutableSortedSet()
                          .Add(oldest);

            var unreachable = ImmutableHashSet <Member> .Empty.Add(oldest);

            var state    = new CurrentClusterState().Copy(members, unreachable);
            var strategy = new KeepOldestDowningStrategy();

            var victims = strategy.GetVictims(state);

            victims.ToImmutableHashSet().SetEquals(members)
            .Should().BeTrue("When we don't have the oldest node, down ourselves");
        }
Esempio n. 20
0
        private void Stable(CurrentClusterState clusterState)
        {
            Receive <IClusterDomainEvent>(msg =>
            {
                Stash.Stash();
                Become(() => WaitingForStability(clusterState));
                Stash.UnstashAll();
            });

            if (clusterState.Leader != null && clusterState.Leader.Equals(cluster.SelfAddress))
            {
                log.Info($"Checking downing strategy {downingStrategy.GetType().Name} for leader {clusterState.Leader} on node {cluster.SelfAddress}");

                foreach (var victim in downingStrategy.GetVictims(clusterState))
                {
                    log.Warning($"Downing victim {victim}");
                    cluster.Down(victim.Address);
                }
            }
        }
Esempio n. 21
0
        public void ShouldDownUnreachablesInOldestPartition()
        {
            var oldest = TestUtils.CreateMembers(MemberStatus.Up)
                         .Take(3)
                         .ToImmutableSortedSet();

            var newest = TestUtils.CreateMembers(MemberStatus.Up)
                         .Take(2)
                         .ToImmutableSortedSet();

            var members     = oldest.Union(newest);
            var unreachable = newest.ToImmutableHashSet();

            var state    = new CurrentClusterState().Copy(members, unreachable);
            var strategy = new KeepOldestDowningStrategy();

            var victims = strategy.GetVictims(state);

            victims.ToImmutableHashSet().SetEquals(unreachable)
            .Should().BeTrue("When we have the oldest node, the unreachable nodes should be downed");
        }
Esempio n. 22
0
        public void ShouldDownUnreachableWhenNoOldest()
        {
            var oldest = TestUtils.CreateMembers(MemberStatus.Up)
                         .Take(3)
                         .ToImmutableSortedSet();

            var members = TestUtils.CreateMembers(MemberStatus.Up)
                          .Take(5)
                          .ToImmutableSortedSet();

            var unreachable = members.Take(2).ToImmutableHashSet();

            var state = new CurrentClusterState().Copy(members, unreachable);

            //There will be no oldest when constrained to this role
            var strategy = new KeepOldestDowningStrategy(role: "SomeRole");

            var victims = strategy.GetVictims(state);

            victims.ToImmutableHashSet().SetEquals(unreachable)
            .Should().BeTrue("When there isn't an oldest node, the unreachable nodes should be downed");
        }
Esempio n. 23
0
 public IEnumerable <Member> GetVictims(CurrentClusterState clusterState)
 {
     return(Enumerable.Empty <Member>());
 }
Esempio n. 24
0
        private void WaitingForStability(CurrentClusterState clusterState)
        {
            log.Debug($"Waiting {stableAfter.TotalSeconds} seconds for cluster stability");

            var timeoutHandle =
                Context.System.Scheduler.ScheduleTellOnceCancelable(
                    stableAfter,
                    Self,
                    new Timeout(),
                    Self);

            Receive <Timeout>(msg =>
            {
                Become(() => Stable(clusterState));
            });

            Receive <IClusterDomainEvent>(msg =>
            {
                timeoutHandle.CancelIfNotNull();

                CurrentClusterState newState;

                switch (msg)
                {
                case LeaderChanged changed:
                    newState = clusterState.Copy(leader: changed.Leader);
                    break;

                case RoleLeaderChanged changed:
                    var roleLeaders =
                        clusterState.AllRoles
                        .Select(role => (Role: role, Leader: clusterState.RoleLeader(role)))
                        .Where(t => t.Leader != null)
                        .ToImmutableDictionary(t => t.Role, t => t.Leader);

                    newState = clusterState.Copy(roleLeaderMap: roleLeaders.SetItem(changed.Role, changed.Leader));
                    break;

                case MemberRemoved member:
                    newState = clusterState.Copy(
                        members: clusterState.Members.Remove(member.Member),
                        unreachable: clusterState.Unreachable.Remove(member.Member));
                    break;

                case MemberUp member:
                    newState = clusterState.Copy(members: clusterState.Members.Add(member.Member));
                    break;

                case UnreachableMember member:
                    newState = clusterState.Copy(unreachable: clusterState.Unreachable.Add(member.Member));
                    break;

                case ReachableMember member:
                    newState = clusterState.Copy(unreachable: clusterState.Unreachable.Remove(member.Member));
                    break;

                default:
                    newState = clusterState;
                    break;
                }

                Become(() => WaitingForStability(newState));
            });
        }
Esempio n. 25
0
        public IEnumerable <Member> GetVictims(CurrentClusterState clusterState)
        {
            _system.EventStream.Publish(new Execution());

            return(Enumerable.Empty <Member>());
        }