For my work I need to make some modifications to an in-house raft library 
(https://raft.github.io/). Without delving too deep into the algorithm, one 
of the stages in the algorithm is a "candidate" goroutine that performs an 
assessment of  whether it should be able to transition to a "leader" state. 

There are some rules around how the candidate performs this assessment and 
one of the rules is to periodically run an "election" where the candidate 
seeks votes from its peers and if it receives the majority of votes, it 
declares itself a leader. The algorithm is a bit more nuanced to this but 
for the sake of simplification I am focusing just on the part where the 
election proceeds as follows:

1. Starts the election process.
2. Sets an election timer, which periodically expires, if the candidate has 
not received any votes during that period, it will reset the deadline and 
start the election all over again. 

With that in mind I modeled my implementation as follows:

func (f *candidate) startElection(ctx context.Context) <-chan struct{} {
       //Channel that signals to the caller when the election is done 
       electionCompletionChan := make(chan struct{})
        go func() {
              //Instead of busy-looping, running the poll logic at 
predefined intervals
              ticker := time.NewTicker(config.PollDuration * time.Second)
              defer ticker.Stop()
              //Reset the election deadline. SetDeadline takes the current 
time and sets a random offset                //in the future
              f.raftTimer.SetDeadline(time.Now())
              //callElection makes the RPC to its peers requesting votes 
and upon completion, 
              //returns its status to the voteStatusChan channel
              voteStatusChan := f.callElection()
             //Polling  
             for tick := range ticker.C {
              select {
                   //The caller called cancel on the context
                    case <-ctx.Done():
                           log.Println("Cancelling election")
                           //Send an empty struct signaling the end of the 
election process
                           electionCompletionChan <- struct{}{}
                           return
                   //Checking whether all the votes have been received 
                  case voteStatus := <-voteStatusChan:
                    {
                           switch voteStatus {
                               //Majority of peers agreed that the 
candidate should be the leader  
                               case voter.Leader:
                                       //Flip the state to leader
                                       f.leaderTrigger <- LeaderTrigger{}
                                       //Conclude the election process
                                       electionCompletionChan <- struct{}{}
                                       return
                               default:
                                      //Split vote or loss: Do nothing, 
re-election will be triggered
                           }
                     }
                  default:
                        //Check whether the election deadline was exceeded
                        if tick.After(f.raftTimer.GetDeadline()) {
                             //Reset the deadline
                              f.raftTimer.SetDeadline(tick)
                             //Once again make the callElection to redo the 
election
                              voteStatusChan = f.callElection()
                       }
            }
       }
    }()
    return electionCompletionChan
}

There are a few things that I am worried about in the above given snippet. 
The first thing is whether I am in alignment with golang's idioms while 
modeling this process using channels and the second thing is where I am 
resetting the voteStatusChan by creating channels within the poll loop. 
Something about creating new channels for every tick of the timer seems to 
be wasteful (I don't have a particularly nuanced understanding of how 
unbounded channel creations will tax the garbage collector or if there are 
other dangers lurking in the corner by taking this approach)

It will be great to get some feedback on what I may be doing wrong here.

Thanks

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/c860d984-9c24-478a-b1fc-c554efcf264fn%40googlegroups.com.

Reply via email to