Example #1
0
        public Node MakeNode(ActorSystem system)
        {
            var cluster = Cluster.Get(system);
            int uid     = cluster.SelfUniqueAddress.Uid;
            var node    = new Node(uid);

            ActionBroker.SetLeader(system.ActorOf <LeaderActor>("leader"));
            ActionBroker.SetFollower(system.ActorOf <FollowerActor>("follower"));
            ActionBroker.SetCandidate(system.ActorOf <CandidateActor>("candidate"));
            ActionBroker.SetElection(system.ActorOf <ElectionCycleActor>("electionCycle"));
            ActionBroker.SetHeartbeat(system.ActorOf <HeartbeatActor>("heartbeat"));
            ActionBroker.SetStatusBroadcast(system.ActorOf <StatusBroadcastActor>("status"));

            return(node);
        }
Example #2
0
        public Node(int clusterUniqueId)
        {
            ProcessId  = Process.GetCurrentProcess().Id;
            ClusterUid = clusterUniqueId;
            Log.Information("{0}", $"My Uid is {ClusterUid}");
            LogEntries = new List <LogEntry>();

            NodeEvents.OnElectionDurationChanged = dur => ElectionDuration = dur;
            NodeEvents.OnElectionElapsed         = el => ElectionElapsed = el;

            NodeEvents.OnElectionTimeout = () => {
                //step up as candidate
                //ask for vote
                if (Role == Roles.Follower)
                {
                    Role = Roles.Candidate;
                    Term++;
                    Votes = 0;

                    Log.Information("{0}", $"Starting election for term {Term}");
                    ActionBroker.StopElectionTimer();
                    ActionBroker.AskForVote(Term);
                    ActionBroker.StartWaitForVote();
                }
            };

            NodeEvents.OnGotVote = (uid, term) =>
            {
                //if got more than majority vote, then becomes leader
                //start sending heartbeat
                if (term == Term)
                {
                    Votes++;
                }

                Log.Information("{0}", $"Got {Votes}/{Majority} votes for term {term} from {uid}");
                if (Votes >= Majority)
                {
                    Log.Information("{0}", "Elected!");
                    Role            = Roles.Leader;
                    CurrentLeaderId = ClusterUid;
                    ActionBroker.StopWaitForVote();
                    ActionBroker.StartHeartbeat();
                }
            };

            NodeEvents.OnHeartbeat = (senderpath, hb) => {
                //resets election time
                //otherwise becomes candidate and send request for votes
                ActionBroker.ResetElectionTimer();

                //if heartbeat has term equal or bigger than self, then step down
                if (hb.Term >= Term)
                {
                    //need to roll back changes and take match leader's log entries
                    if (Role != Roles.Follower)
                    {
                        Log.Information("{0}", "Stepping down");
                        Role = Roles.Follower;
                        ActionBroker.StopHeartbeat();
                        ActionBroker.StartElectionTimer();
                    }

                    if (hb.Term != Term)
                    {
                        Log.Information("{0}", $"Updating from term {Term} to {hb.Term}");
                        Term = hb.Term;
                    }
                }

                CurrentLeaderId = hb.SenderId;

                if (Role == Roles.Follower)
                {
                    ActionBroker.SendHeartbeatResponse(hb.Id, hb.SenderId, senderpath, hb.Term, hb.LogIndex);
                }
            };

            NodeEvents.OnJoinedCluster = () => {
                if (Role != Roles.Leader)
                {
                    Log.Information("{0}", "Starting election timer");
                    ActionBroker.StartElectionTimer();
                }
            };

            NodeEvents.OnVoteRequest = vr =>
            {
                //if not voted this term and is not a leader, then vote for the candidate
                if (_votedForTerm < vr.Term && Role != Roles.Leader)
                {
                    if (vr.SenderId != ClusterUid)
                    {
                        Log.Information("{0}", $"Vote request from candidate {vr.SenderId} for term {vr.Term}");
                    }
                    else
                    {
                        Log.Information("{0}", $"Vote request from self in term {vr.Term}");
                    }

                    _votedForTerm = vr.Term;

                    return(true);
                }
                else
                {
                    Log.Information("{0}", $"Not voting. {vr.SenderId} asking for term {vr.Term}, last voted for {_votedForTerm} and role is {Role.ToString()}");
                    return(false);
                }
            };

            NodeEvents.OnWaitForVoteTimeout = () =>
            {
                //restart election time
                Role = Roles.Follower;
                ActionBroker.ResetElectionTimer();
                ActionBroker.StartElectionTimer();
            };

            NodeEvents.OnMemberChanged = count => {
                //update majority
                Majority = (count + 1) / 2;
                Log.Information("{0}", $"Majority is now {Majority}");
            };
        }
Example #3
0
 public void Stop(TimeSpan timeSpan)
 {
     ActionBroker.Stop(timeSpan);
 }
Example #4
0
 public void OnKill()
 {
     ActionBroker.SendTerminateSignal();
 }