From 4657b27a60b0b64d467a88cca41a08352067f76b Mon Sep 17 00:00:00 2001 From: Nishant Totla Date: Fri, 26 Jan 2018 14:23:39 -0800 Subject: [PATCH] Make sure that task reaper stopChan is closed no more than one time Signed-off-by: Nishant Totla --- manager/orchestrator/taskreaper/task_reaper.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/manager/orchestrator/taskreaper/task_reaper.go b/manager/orchestrator/taskreaper/task_reaper.go index d702783833..ad083abb07 100644 --- a/manager/orchestrator/taskreaper/task_reaper.go +++ b/manager/orchestrator/taskreaper/task_reaper.go @@ -2,6 +2,7 @@ package taskreaper import ( "sort" + "sync" "time" "github.com/docker/swarmkit/api" @@ -24,6 +25,9 @@ const ( type TaskReaper struct { store *store.MemoryStore + // closeOnce ensures that stopChan is closed only once + closeOnce sync.Once + // taskHistory is the number of tasks to keep taskHistory int64 @@ -281,9 +285,14 @@ func (tr *TaskReaper) tick() { } // Stop stops the TaskReaper and waits for the main loop to exit. +// Stop can be called in two instances. One when the manager is +// shutting down, and the other when the manager (the leader) is +// becoming a follower. Since these two instances could race with +// each other, we must ensure that TaskReaper.Stop() is called +// only once to avoid a panic. func (tr *TaskReaper) Stop() { - // TODO(dperny) calling stop on the task reaper twice will cause a panic - // because we try to close a channel that will already have been closed. - close(tr.stopChan) + tr.closeOnce.Do(func() { + close(tr.stopChan) + }) <-tr.doneChan }