shutdown.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. //go:build linux || darwin
  2. // +build linux darwin
  3. package proc
  4. import (
  5. "os"
  6. "os/signal"
  7. "sync"
  8. "syscall"
  9. "time"
  10. "github.com/zeromicro/go-zero/core/logx"
  11. "github.com/zeromicro/go-zero/core/threading"
  12. )
  13. const (
  14. wrapUpTime = time.Second
  15. // why we use 5500 milliseconds is because most of our queue are blocking mode with 5 seconds
  16. waitTime = 5500 * time.Millisecond
  17. )
  18. var (
  19. wrapUpListeners = new(listenerManager)
  20. shutdownListeners = new(listenerManager)
  21. delayTimeBeforeForceQuit = waitTime
  22. )
  23. // AddShutdownListener adds fn as a shutdown listener.
  24. // The returned func can be used to wait for fn getting called.
  25. func AddShutdownListener(fn func()) (waitForCalled func()) {
  26. return shutdownListeners.addListener(fn)
  27. }
  28. // AddWrapUpListener adds fn as a wrap up listener.
  29. // The returned func can be used to wait for fn getting called.
  30. func AddWrapUpListener(fn func()) (waitForCalled func()) {
  31. return wrapUpListeners.addListener(fn)
  32. }
  33. // SetTimeToForceQuit sets the waiting time before force quitting.
  34. func SetTimeToForceQuit(duration time.Duration) {
  35. delayTimeBeforeForceQuit = duration
  36. }
  37. func gracefulStop(signals chan os.Signal) {
  38. signal.Stop(signals)
  39. logx.Info("Got signal SIGTERM, shutting down...")
  40. go wrapUpListeners.notifyListeners()
  41. time.Sleep(wrapUpTime)
  42. go shutdownListeners.notifyListeners()
  43. time.Sleep(delayTimeBeforeForceQuit - wrapUpTime)
  44. logx.Infof("Still alive after %v, going to force kill the process...", delayTimeBeforeForceQuit)
  45. syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
  46. }
  47. type listenerManager struct {
  48. lock sync.Mutex
  49. waitGroup sync.WaitGroup
  50. listeners []func()
  51. }
  52. func (lm *listenerManager) addListener(fn func()) (waitForCalled func()) {
  53. lm.waitGroup.Add(1)
  54. lm.lock.Lock()
  55. lm.listeners = append(lm.listeners, func() {
  56. defer lm.waitGroup.Done()
  57. fn()
  58. })
  59. lm.lock.Unlock()
  60. return func() {
  61. lm.waitGroup.Wait()
  62. }
  63. }
  64. func (lm *listenerManager) notifyListeners() {
  65. lm.lock.Lock()
  66. defer lm.lock.Unlock()
  67. group := threading.NewRoutineGroup()
  68. for _, listener := range lm.listeners {
  69. group.RunSafe(listener)
  70. }
  71. group.Wait()
  72. }