Internal API cleanup, vote timing jitter

This commit is contained in:
Ian Gulliver
2023-06-03 22:31:09 -07:00
parent 3cebbc3425
commit d641fdca40
2 changed files with 38 additions and 31 deletions

View File

@@ -20,8 +20,8 @@ type Candidate struct {
numVoters int
signingKey []byte
stop chan<- bool
done <-chan bool
stop chan bool
done chan bool
resp voteResponse
c chan<- CandidateState
@@ -38,8 +38,6 @@ var (
)
func NewCandidate(numVoters int, signingKey string) *Candidate {
stop := make(chan bool)
done := make(chan bool)
change := make(chan CandidateState, 100)
c := &Candidate{
@@ -47,15 +45,15 @@ func NewCandidate(numVoters int, signingKey string) *Candidate {
numVoters: numVoters,
signingKey: []byte(signingKey),
votes: map[string]*vote{},
stop: stop,
done: done,
stop: make(chan bool),
done: make(chan bool),
c: change,
resp: voteResponse{
CandidateID: uniuri.New(),
},
}
go c.loop(stop, done)
go c.loop()
return c
}
@@ -237,14 +235,14 @@ func (c *Candidate) update(state CandidateState) {
c.c <- state
}
func (c *Candidate) loop(stop <-chan bool, done chan<- bool) {
func (c *Candidate) loop() {
t := time.NewTicker(1 * time.Second)
defer t.Stop()
defer close(done)
defer close(c.done)
for {
select {
case <-stop:
case <-c.stop:
return
case <-t.C:

View File

@@ -4,6 +4,7 @@ import (
"crypto/hmac"
"encoding/json"
"log"
"math/rand"
"time"
"github.com/dchest/uniuri"
@@ -12,12 +13,16 @@ import (
)
type Voter struct {
// used by user and loop() goroutines
update chan time.Duration
done chan bool
// used by loop() goroutine only
client *resty.Client
signingKey []byte
update chan<- time.Duration
done <-chan bool
vote vote
candidates []*Candidate
period time.Duration
}
type vote struct {
@@ -36,22 +41,20 @@ type voteResponse struct {
}
func NewVoter(url string, signingKey string) *Voter {
update := make(chan time.Duration)
done := make(chan bool)
v := &Voter{
client: resty.New().
SetCloseConnection(true).
SetBaseURL(url),
signingKey: []byte(signingKey),
update: update,
done: done,
update: make(chan time.Duration),
done: make(chan bool),
vote: vote{
VoterID: uniuri.New(),
},
period: 5 * time.Second,
}
go v.loop(update, done)
go v.loop()
return v
}
@@ -65,40 +68,42 @@ func (v *Voter) AddCandidate(c *Candidate) {
v.candidates = append(v.candidates, c)
}
func (v *Voter) loop(update <-chan time.Duration, done chan<- bool) {
// TODO: Need a JitterTicker
t := time.NewTicker(5 * time.Second)
defer t.Stop()
defer close(done)
func (v *Voter) loop() {
defer close(v.done)
for {
if !v.poll(update, t) {
if !v.poll() {
break
}
}
}
func (v *Voter) poll(update <-chan time.Duration, t *time.Ticker) bool {
func (v *Voter) poll() bool {
// mean: v.period, max: v.period*2
t := time.NewTimer(randDurationN(v.period * 2))
defer t.Stop()
t2 := &time.Timer{}
if v.vote.NumPollsSinceChange <= 10 {
t2 = time.NewTimer(100 * time.Millisecond)
// mean: 100ms, max: 200ms
t2 = time.NewTimer(randDurationN(100 * time.Millisecond * 2))
defer t2.Stop()
}
select {
case <-t2.C:
v.sendVote()
case <-t.C:
v.sendVote()
case period, ok := <-update:
case <-t2.C:
v.sendVote()
case period, ok := <-v.update:
if !ok {
return false
}
t.Reset(period)
v.period = period
}
return true
@@ -169,3 +174,7 @@ func (v *Voter) sendVote() {
func (v *Voter) log(format string, args ...any) {
log.Printf("[voter] "+format, args...)
}
func randDurationN(n time.Duration) time.Duration {
return time.Duration(rand.Int63n(int64(n))) //nolint:gosec
}