doFollow :: (RaftLog l e v) => Raft l e v -> IO ()
doFollow vRaft = do
    doSynchronize vRaft onRequest alwaysContinue
    where
        onRequest raft req = do
            let log = raftLog raft
                nextIndex = (1 + (logIndex $ aePreviousTime req))
                count = length $ aeEntries req
            if count > 0
                then infoM _log $ printf "%v: Appending %d at %d" (raftName raft) count nextIndex
                else return ()
            newLog <- appendEntries log nextIndex (aeEntries req)
            if count > 0
                then infoM _log $ printf "%v: Appended %d at %d" (raftName raft) count (lastAppended newLog)
                else return ()
            updatedRaft <- atomically $ do
                    preCommitConfigurationChange vRaft (aeEntries req)
                    modifyTVar (raftContext vRaft) $ \oldRaft -> setRaftLog newLog oldRaft
                    readTVar (raftContext vRaft)
            if (logIndex $ aeCommittedTime req) > (lastCommitted $ raftLog updatedRaft)
                then do
                    infoM _log $ printf "%v: Committing at %d" (raftName raft) (logIndex $ aeCommittedTime req)
                    (committedLog,committedState) <- commitEntries (raftLog updatedRaft) (logIndex $ aeCommittedTime req) (raftState updatedRaft)
                    infoM _log $ printf "%v: Committed at %d" (raftName raft) (lastCommitted committedLog)
                    (checkpointedLog,checkpointedState) <- checkpoint committedLog committedState
                    checkpointedRaft <- atomically $ do
                        modifyTVar (raftContext vRaft) $ \oldRaft ->
                                setRaftLog checkpointedLog
                                $ setRaftState checkpointedState oldRaft
                        readTVar (raftContext vRaft)
                    return checkpointedRaft
                else return updatedRaft
        alwaysContinue _ = True
doFollow :: (RaftLog l e v) => Raft l e v -> IO ()
doFollow vRaft = do
    doSynchronize vRaft onRequest alwaysContinue
    where
        onRequest raft req = do
            let log = raftLog raft
                nextIndex = (1 + (logIndex $ aePreviousTime req))
                count = length $ aeEntries req
            if count > 0
                then infoM _log $ printf "%v: Appending %d at %d" (raftName raft) count nextIndex
                else return ()
            newLog <- appendEntries log nextIndex (aeEntries req)
            if count > 0
                then infoM _log $ printf "%v: Appended %d at %d" (raftName raft) count (lastAppended newLog)
                else return ()
            updatedRaft <- atomically $ do
                    preCommitConfigurationChange vRaft (aeEntries req)
                    modifyTVar (raftContext vRaft) $ \oldRaft -> setRaftLog newLog oldRaft
                    readTVar (raftContext vRaft)
            if (logIndex $ aeCommittedTime req) > (lastCommitted $ raftLog updatedRaft)
                then do
                    infoM _log $ printf "%v: Committing at %d" (raftName raft) (logIndex $ aeCommittedTime req)
                    (committedLog,committedState) <- commitEntries (raftLog updatedRaft) (logIndex $ aeCommittedTime req) (raftState updatedRaft)
                    infoM _log $ printf "%v: Committed at %d" (raftName raft) (lastCommitted committedLog)
                    (checkpointedLog,checkpointedState) <- checkpoint committedLog committedState
                    checkpointedRaft <- atomically $ do
                        modifyTVar (raftContext vRaft) $ \oldRaft ->
                                setRaftLog checkpointedLog
                                $ setRaftState checkpointedState oldRaft
                        readTVar (raftContext vRaft)
                    return checkpointedRaft
                else return updatedRaft
        alwaysContinue _ = True
doFollow vRaft = do
    doSynchronize vRaft onRequest alwaysContinue
    where
        onRequest raft req = do
            let log = raftLog raft
                nextIndex = (1 + (logIndex $ aePreviousTime req))
                count = length $ aeEntries req
            if count > 0
                then infoM _log $ printf "%v: Appending %d at %d" (raftName raft) count nextIndex
                else return ()
            newLog <- appendEntries log nextIndex (aeEntries req)
            if count > 0
                then infoM _log $ printf "%v: Appended %d at %d" (raftName raft) count (lastAppended newLog)
                else return ()
            updatedRaft <- atomically $ do
                    preCommitConfigurationChange vRaft (aeEntries req)
                    modifyTVar (raftContext vRaft) $ \oldRaft -> setRaftLog newLog oldRaft
                    readTVar (raftContext vRaft)
            if (logIndex $ aeCommittedTime req) > (lastCommitted $ raftLog updatedRaft)
                then do
                    infoM _log $ printf "%v: Committing at %d" (raftName raft) (logIndex $ aeCommittedTime req)
                    (committedLog,committedState) <- commitEntries (raftLog updatedRaft) (logIndex $ aeCommittedTime req) (raftState updatedRaft)
                    infoM _log $ printf "%v: Committed at %d" (raftName raft) (lastCommitted committedLog)
                    (checkpointedLog,checkpointedState) <- checkpoint committedLog committedState
                    checkpointedRaft <- atomically $ do
                        modifyTVar (raftContext vRaft) $ \oldRaft ->
                                setRaftLog checkpointedLog
                                $ setRaftState checkpointedState oldRaft
                        readTVar (raftContext vRaft)
                    return checkpointedRaft
                else return updatedRaft
        alwaysContinue _ = True