func (d *Dinghy) follower() error {
	d.logger.Println("entering follower state, leader id", d.State.LeaderID())
	d.mu.Lock()
	if err := d.OnFollower(); err != nil {
		d.logger.Errorln("executing OnFollower", err)
		d.mu.Unlock()
		return err
	}
	d.mu.Unlock()
LOOP:
	for {
		select {
		case <-d.stopChan:
			return nil
		case newState := <-d.State.StateChanged():
			if newState == StateFollower {
				continue
			}
			d.logger.Println("follower state changed to", d.State.StateString(newState))
			return nil
		case <-d.State.HeartbeatReset():
			d.logger.Println("heartbeat reset")
			continue LOOP
		case aer := <-d.State.AppendEntriesEvent():
			d.logger.Println(d.State.StateString(d.State.State()), "got AppendEntries from leader", aer)
			continue LOOP
		case h := <-d.State.HeartbeatTickRandom():
			// https://raft.github.io/raft.pdf
			// If a follower receives no communication over a period of time
			// called the election timeout, then it assumes there is no viable
			// leader and begins an election to choose a new leader.
			// To begin an election, a follower increments its current
			// term and transitions to candidate state.
			d.logger.Println("follower heartbeat timeout, transitioning to candidate", h)
			d.State.VotedFor(NoVote)
			d.State.LeaderID(UnknownLeaderID)
			d.State.Term(d.State.Term() + 1)
			d.State.State(StateCandidate)
			return nil
		}
	}
}
// follower will wait for an AppendEntries from the leader and on expiration will begin
// the process of leader election with a RequestVote.
follower will wait for an AppendEntries from the leader and on expiration will begin
the process of leader election with a RequestVote.
// follower will wait for an AppendEntries from the leader and on expiration will begin // the process of leader election with a RequestVote .
func (d *Dinghy) follower() error {
	d.logger.Println("entering follower state, leader id", d.State.LeaderID())
	d.mu.Lock()
	if err := d.OnFollower(); err != nil {
		d.logger.Errorln("executing OnFollower", err)
		d.mu.Unlock()
		return err
	}
	d.mu.Unlock()
LOOP:
	for {
		select {
		case <-d.stopChan:
			return nil
		case newState := <-d.State.StateChanged():
			if newState == StateFollower {
				continue
			}
			d.logger.Println("follower state changed to", d.State.StateString(newState))
			return nil
		case <-d.State.HeartbeatReset():
			d.logger.Println("heartbeat reset")
			continue LOOP
		case aer := <-d.State.AppendEntriesEvent():
			d.logger.Println(d.State.StateString(d.State.State()), "got AppendEntries from leader", aer)
			continue LOOP
		case h := <-d.State.HeartbeatTickRandom():
			d.logger.Println("follower heartbeat timeout, transitioning to candidate", h)
			d.State.VotedFor(NoVote)
			d.State.LeaderID(UnknownLeaderID)
			d.State.Term(d.State.Term() + 1)
			d.State.State(StateCandidate)
			return nil
		}
	}
}
func ( d * Dinghy ) follower ( ) error { d . logger . Println ( " " , d . State . LeaderID ( ) ) d . mu . Lock ( ) if err := d . OnFollower ( ) ; err != nil { d . logger . Errorln ( " " , err ) d . mu . Unlock ( ) return err } d . mu . Unlock ( ) LOOP : for { select { case <- d . stopChan : return nil case newState := <- d . State . StateChanged ( ) : if newState == StateFollower { continue } d . logger . Println ( " " , d . State . StateString ( newState ) ) return nil case <- d . State . HeartbeatReset ( ) : d . logger . Println ( " " ) continue LOOP case aer := <- d . State . AppendEntriesEvent ( ) : d . logger . Println ( d . State . StateString ( d . State . State ( ) ) , " " , aer ) continue LOOP case h := <- d . State . HeartbeatTickRandom ( ) : d . logger . Println ( " " , h ) d . State . VotedFor ( NoVote ) d . State . LeaderID ( UnknownLeaderID ) d . State . Term ( d . State . Term ( ) + 1 ) d . State . State ( StateCandidate ) return nil } } }
follower will wait for an AppendEntries from the leader and on expiration will begin
the process of leader election with a RequestVote.
follower will wait for an AppendEntries from the leader and on expiration will begin the process of leader election with a RequestVote .
// https://raft.github.io/raft.pdf // If a follower receives no communication over a period of time // called the election timeout, then it assumes there is no viable // leader and begins an election to choose a new leader. // To begin an election, a follower increments its current // term and transitions to candidate state.