Skip to content

Commit

Permalink
Fix false positive race tests by gating all R/W access to timers behi…
Browse files Browse the repository at this point in the history
…nd synchronization (#875)
  • Loading branch information
Crystal Lemire authored Dec 11, 2023
1 parent 06f1fef commit 0b6a974
Showing 1 changed file with 18 additions and 1 deletion.
19 changes: 18 additions & 1 deletion protocol/daemons/server/types/health_checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,21 @@ func (u *healthCheckerMutableState) SchedulePoll(nextPollDelay time.Duration) {
u.timer.Reset(nextPollDelay)
}

// InitializePolling schedules the first poll for the health-checkable service. This method is meant to be called
// immediately after initializing the health checker mutable state. This method is synchronized.
func (u *healthCheckerMutableState) InitializePolling(firstPollDelay time.Duration, pollFunc func()) {
u.lock.Lock()
defer u.lock.Unlock()

// If the timer is already initialized, don't initialize it again.
if u.timer != nil {
return
}

// The first poll is scheduled after a custom delay to allow the service to initialize.
u.timer = time.AfterFunc(firstPollDelay, pollFunc)
}

// Stop stops the health checker. This method is synchronized.
func (u *healthCheckerMutableState) Stop() {
u.lock.Lock()
Expand Down Expand Up @@ -204,7 +219,9 @@ func StartNewHealthChecker(
}

// The first poll is scheduled after the startup grace period to allow the service to initialize.
checker.mutableState.timer = time.AfterFunc(startupGracePeriod, checker.Poll)
// We initialize the timer and schedule a poll outside of object creation in order to avoid data races for
// extremely short startup grace periods.
checker.mutableState.InitializePolling(startupGracePeriod, checker.Poll)

return checker
}

0 comments on commit 0b6a974

Please sign in to comment.