etcd: scheduler: Use atomic to prevent race

This code should be rewritten, but in the meantime, at least avoid the
race detector issues.
This commit is contained in:
James Shubin
2025-08-20 14:52:58 -04:00
parent bed7e6be79
commit b02363ad0d

View File

@@ -37,6 +37,7 @@ import (
"sort" "sort"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"github.com/purpleidea/mgmt/util/errwrap" "github.com/purpleidea/mgmt/util/errwrap"
@@ -245,7 +246,7 @@ func Schedule(client *etcd.Client, path string, hostname string, opts ...Option)
mutex := &sync.Mutex{} mutex := &sync.Mutex{}
var campaignClose chan struct{} var campaignClose chan struct{}
var campaignRunning bool campaignRunning := &atomic.Bool{}
// goroutine to vote for someone as scheduler! each participant must be // goroutine to vote for someone as scheduler! each participant must be
// able to run this or nobody will be around to vote if others are down // able to run this or nobody will be around to vote if others are down
campaignFunc := func() { campaignFunc := func() {
@@ -363,18 +364,18 @@ func Schedule(client *etcd.Client, path string, hostname string, opts ...Option)
//} //}
if elected != hostname { // not me! if elected != hostname { // not me!
// start up the campaign function // start up the campaign function
if !campaignRunning { if !campaignRunning.Load() {
campaignClose = make(chan struct{}) campaignClose = make(chan struct{})
campaignFunc() // run campaignFunc() // run
campaignRunning = true campaignRunning.Store(true)
} }
continue // someone else does the scheduling... continue // someone else does the scheduling...
} else { // campaigning while i am it loops fast } else { // campaigning while i am it loops fast
// shutdown the campaign function // shutdown the campaign function
if campaignRunning { if campaignRunning.Load() { // XXX: RACE READ
close(campaignClose) close(campaignClose)
wg.Wait() wg.Wait()
campaignRunning = false campaignRunning.Store(false)
} }
} }
@@ -559,10 +560,10 @@ func Schedule(client *etcd.Client, path string, hostname string, opts ...Option)
leaderResult, err := election.Leader(ctx) leaderResult, err := election.Leader(ctx)
if err == concurrency.ErrElectionNoLeader { if err == concurrency.ErrElectionNoLeader {
// start up the campaign function // start up the campaign function
if !campaignRunning { if !campaignRunning.Load() {
campaignClose = make(chan struct{}) campaignClose = make(chan struct{})
campaignFunc() // run campaignFunc() // run
campaignRunning = true campaignRunning.Store(true) // XXX: RACE WRITE
} }
} }
if options.debug { if options.debug {