checker: fix ResumeBackend leaking goroutine on non-paused backend; v1.0.2
Calling ResumeBackend on a backend that wasn't actually paused (state != StatePaused) would overwrite w.cancel and spawn a fresh probe goroutine without cancelling the old one, leaving two probe loops running for the same backend until process exit. The guard now mirrors EnableBackend's early-return on a non-target state.
This commit is contained in:
@@ -416,6 +416,11 @@ func (c *Checker) PauseBackend(name string) (BackendSnapshot, error) {
|
||||
// goroutine is started and the backend re-enters StateUnknown. The existing
|
||||
// transition history is preserved.
|
||||
// Returns an error if the backend is not found or is disabled.
|
||||
//
|
||||
// No-ops when the backend isn't paused: PauseBackend is what cancels the
|
||||
// probe goroutine, so if we started a fresh one here unconditionally we'd
|
||||
// overwrite w.cancel with a new cancel func and orphan the old goroutine —
|
||||
// two probe loops would then run for the same backend until process exit.
|
||||
func (c *Checker) ResumeBackend(name string) (BackendSnapshot, error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
@@ -426,6 +431,9 @@ func (c *Checker) ResumeBackend(name string) (BackendSnapshot, error) {
|
||||
if !w.entry.Enabled {
|
||||
return BackendSnapshot{}, fmt.Errorf("backend %q is disabled; enable it first", name)
|
||||
}
|
||||
if w.backend.State != health.StatePaused {
|
||||
return BackendSnapshot{Health: w.backend, Config: w.entry}, nil
|
||||
}
|
||||
maxHistory := c.cfg.HealthChecker.TransitionHistory
|
||||
if w.backend.Resume(maxHistory) {
|
||||
t := w.backend.Transitions[0]
|
||||
|
||||
Reference in New Issue
Block a user