chore: refactor shutdown config, to prevent setting zero values (#4533)

Signed-off-by: kevin <wanjunfeng@gmail.com>
This commit is contained in:
Kevin Wan
2025-01-01 20:46:51 +08:00
committed by GitHub
parent 22a41cacc7
commit 28a001c5f9
3 changed files with 83 additions and 23 deletions

View File

@@ -13,19 +13,26 @@ import (
"github.com/zeromicro/go-zero/core/threading" "github.com/zeromicro/go-zero/core/threading"
) )
type ProcConf struct { const (
WrapUpTime time.Duration `json:",default=1s"` defaultWrapUpTime = time.Second
WaitTime time.Duration `json:",default=5.5s"` // why we use 5500 milliseconds is because most of our queue are blocking mode with 5 seconds
} defaultWaitTime = 5500 * time.Millisecond
)
var ( var (
wrapUpListeners = new(listenerManager) wrapUpListeners = new(listenerManager)
shutdownListeners = new(listenerManager) shutdownListeners = new(listenerManager)
wrapUpTime = time.Second wrapUpTime = defaultWrapUpTime
// why we use 5500 milliseconds is because most of our queue are blocking mode with 5 seconds waitTime = defaultWaitTime
delayTimeBeforeForceQuit = 5500 * time.Millisecond shutdownLock sync.Mutex
) )
// ShutdownConf defines the shutdown configuration for the process.
type ShutdownConf struct {
WrapUpTime time.Duration `json:",default=1s"`
WaitTime time.Duration `json:",default=5.5s"`
}
// AddShutdownListener adds fn as a shutdown listener. // AddShutdownListener adds fn as a shutdown listener.
// The returned func can be used to wait for fn getting called. // The returned func can be used to wait for fn getting called.
func AddShutdownListener(fn func()) (waitForCalled func()) { func AddShutdownListener(fn func()) (waitForCalled func()) {
@@ -40,12 +47,21 @@ func AddWrapUpListener(fn func()) (waitForCalled func()) {
// SetTimeToForceQuit sets the waiting time before force quitting. // SetTimeToForceQuit sets the waiting time before force quitting.
func SetTimeToForceQuit(duration time.Duration) { func SetTimeToForceQuit(duration time.Duration) {
delayTimeBeforeForceQuit = duration shutdownLock.Lock()
defer shutdownLock.Unlock()
waitTime = duration
} }
func Setup(conf ProcConf) { func Setup(conf ShutdownConf) {
wrapUpTime = conf.WrapUpTime shutdownLock.Lock()
delayTimeBeforeForceQuit = conf.WaitTime defer shutdownLock.Unlock()
if conf.WrapUpTime > 0 {
wrapUpTime = conf.WrapUpTime
}
if conf.WaitTime > 0 {
waitTime = conf.WaitTime
}
} }
// Shutdown calls the registered shutdown listeners, only for test purpose. // Shutdown calls the registered shutdown listeners, only for test purpose.
@@ -67,8 +83,12 @@ func gracefulStop(signals chan os.Signal, sig syscall.Signal) {
time.Sleep(wrapUpTime) time.Sleep(wrapUpTime)
go shutdownListeners.notifyListeners() go shutdownListeners.notifyListeners()
time.Sleep(delayTimeBeforeForceQuit - wrapUpTime) shutdownLock.Lock()
logx.Infof("Still alive after %v, going to force kill the process...", delayTimeBeforeForceQuit) remainingTime := waitTime - wrapUpTime
shutdownLock.Unlock()
time.Sleep(remainingTime)
logx.Infof("Still alive after %v, going to force kill the process...", waitTime)
_ = syscall.Kill(syscall.Getpid(), sig) _ = syscall.Kill(syscall.Getpid(), sig)
} }

View File

@@ -11,8 +11,12 @@ import (
) )
func TestShutdown(t *testing.T) { func TestShutdown(t *testing.T) {
t.Cleanup(restoreSettings)
SetTimeToForceQuit(time.Hour) SetTimeToForceQuit(time.Hour)
assert.Equal(t, time.Hour, delayTimeBeforeForceQuit) shutdownLock.Lock()
assert.Equal(t, time.Hour, waitTime)
shutdownLock.Unlock()
var val int var val int
called := AddWrapUpListener(func() { called := AddWrapUpListener(func() {
@@ -31,8 +35,12 @@ func TestShutdown(t *testing.T) {
} }
func TestShutdownWithMultipleServices(t *testing.T) { func TestShutdownWithMultipleServices(t *testing.T) {
t.Cleanup(restoreSettings)
SetTimeToForceQuit(time.Hour) SetTimeToForceQuit(time.Hour)
assert.Equal(t, time.Hour, delayTimeBeforeForceQuit) shutdownLock.Lock()
assert.Equal(t, time.Hour, waitTime)
shutdownLock.Unlock()
var val int32 var val int32
called1 := AddShutdownListener(func() { called1 := AddShutdownListener(func() {
@@ -49,8 +57,12 @@ func TestShutdownWithMultipleServices(t *testing.T) {
} }
func TestWrapUpWithMultipleServices(t *testing.T) { func TestWrapUpWithMultipleServices(t *testing.T) {
t.Cleanup(restoreSettings)
SetTimeToForceQuit(time.Hour) SetTimeToForceQuit(time.Hour)
assert.Equal(t, time.Hour, delayTimeBeforeForceQuit) shutdownLock.Lock()
assert.Equal(t, time.Hour, waitTime)
shutdownLock.Unlock()
var val int32 var val int32
called1 := AddWrapUpListener(func() { called1 := AddWrapUpListener(func() {
@@ -67,6 +79,8 @@ func TestWrapUpWithMultipleServices(t *testing.T) {
} }
func TestNotifyMoreThanOnce(t *testing.T) { func TestNotifyMoreThanOnce(t *testing.T) {
t.Cleanup(restoreSettings)
ch := make(chan struct{}, 1) ch := make(chan struct{}, 1)
go func() { go func() {
@@ -97,10 +111,36 @@ func TestNotifyMoreThanOnce(t *testing.T) {
} }
func TestSetup(t *testing.T) { func TestSetup(t *testing.T) {
Setup(ProcConf{ t.Run("valid time", func(t *testing.T) {
WrapUpTime: time.Second * 2, defer restoreSettings()
WaitTime: time.Second * 30,
Setup(ShutdownConf{
WrapUpTime: time.Second * 2,
WaitTime: time.Second * 30,
})
shutdownLock.Lock()
assert.Equal(t, time.Second*2, wrapUpTime)
assert.Equal(t, time.Second*30, waitTime)
shutdownLock.Unlock()
})
t.Run("valid time", func(t *testing.T) {
defer restoreSettings()
Setup(ShutdownConf{})
shutdownLock.Lock()
assert.Equal(t, defaultWrapUpTime, wrapUpTime)
assert.Equal(t, defaultWaitTime, waitTime)
shutdownLock.Unlock()
}) })
assert.Equal(t, time.Second*2, wrapUpTime) }
assert.Equal(t, time.Second*30, delayTimeBeforeForceQuit)
func restoreSettings() {
shutdownLock.Lock()
defer shutdownLock.Unlock()
wrapUpTime = defaultWrapUpTime
waitTime = defaultWaitTime
} }

View File

@@ -37,7 +37,7 @@ type (
Prometheus prometheus.Config `json:",optional"` Prometheus prometheus.Config `json:",optional"`
Telemetry trace.Config `json:",optional"` Telemetry trace.Config `json:",optional"`
DevServer DevServerConfig `json:",optional"` DevServer DevServerConfig `json:",optional"`
Proc proc.ProcConf `json:",optional"` Shutdown proc.ShutdownConf `json:",optional"`
} }
) )
@@ -62,7 +62,7 @@ func (sc ServiceConf) SetUp() error {
sc.Telemetry.Name = sc.Name sc.Telemetry.Name = sc.Name
} }
trace.StartAgent(sc.Telemetry) trace.StartAgent(sc.Telemetry)
proc.Setup(sc.Proc) proc.Setup(sc.Shutdown)
proc.AddShutdownListener(func() { proc.AddShutdownListener(func() {
trace.StopAgent() trace.StopAgent()
}) })