From a8f5449cd95c06e8b55b7f776fc826fc7675c1b6 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Wed, 6 Mar 2024 19:50:39 +0800 Subject: [PATCH] Avoid unexpected panic in graceful manager (#29629) There is a fundamental design problem of the "manager" and the "wait group". If nothing has started, the "Wait" just panics: sync: WaitGroup is reused before previous Wait has returned There is no clear solution besides a complete rewriting of the "manager" If there are some mistakes in the app.ini, end users would just see the "panic", but not the real error messages. A real case: #27643 This PR is just a quick fix for the annoying panic problem. (cherry picked from commit 90a3f2d4b7ed3890d9655c0334444f86d89b7b30) --- modules/graceful/manager_unix.go | 10 +++++++++- modules/graceful/manager_windows.go | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/modules/graceful/manager_unix.go b/modules/graceful/manager_unix.go index f4af4993d..edf5fc248 100644 --- a/modules/graceful/manager_unix.go +++ b/modules/graceful/manager_unix.go @@ -59,7 +59,15 @@ func (g *Manager) start() { go func() { defer close(startupDone) // Wait till we're done getting all the listeners and then close the unused ones - g.createServerWaitGroup.Wait() + func() { + // FIXME: there is a fundamental design problem of the "manager" and the "wait group". + // If nothing has started, the "Wait" just panics: sync: WaitGroup is reused before previous Wait has returned + // There is no clear solution besides a complete rewriting of the "manager" + defer func() { + _ = recover() + }() + g.createServerWaitGroup.Wait() + }() // Ignore the error here there's not much we can do with it, they're logged in the CloseProvidedListeners function _ = CloseProvidedListeners() g.notify(readyMsg) diff --git a/modules/graceful/manager_windows.go b/modules/graceful/manager_windows.go index 0248dcb24..ecf30af3f 100644 --- a/modules/graceful/manager_windows.go +++ b/modules/graceful/manager_windows.go @@ -150,7 +150,15 @@ func (g *Manager) awaitServer(limit time.Duration) bool { c := make(chan struct{}) go func() { defer close(c) - g.createServerWaitGroup.Wait() + func() { + // FIXME: there is a fundamental design problem of the "manager" and the "wait group". + // If nothing has started, the "Wait" just panics: sync: WaitGroup is reused before previous Wait has returned + // There is no clear solution besides a complete rewriting of the "manager" + defer func() { + _ = recover() + }() + g.createServerWaitGroup.Wait() + }() }() if limit > 0 { select {