shutdown.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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. // Shutdown calls the registered shutdown listeners, only for test purpose.
  38. func Shutdown() {
  39. shutdownListeners.notifyListeners()
  40. }
  41. // WrapUp wraps up the process, only for test purpose.
  42. func WrapUp() {
  43. wrapUpListeners.notifyListeners()
  44. }
  45. func gracefulStop(signals chan os.Signal) {
  46. signal.Stop(signals)
  47. logx.Info("Got signal SIGTERM, shutting down...")
  48. go wrapUpListeners.notifyListeners()
  49. time.Sleep(wrapUpTime)
  50. go shutdownListeners.notifyListeners()
  51. time.Sleep(delayTimeBeforeForceQuit - wrapUpTime)
  52. logx.Infof("Still alive after %v, going to force kill the process...", delayTimeBeforeForceQuit)
  53. syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
  54. }
  55. type listenerManager struct {
  56. lock sync.Mutex
  57. waitGroup sync.WaitGroup
  58. listeners []func()
  59. }
  60. func (lm *listenerManager) addListener(fn func()) (waitForCalled func()) {
  61. lm.waitGroup.Add(1)
  62. lm.lock.Lock()
  63. lm.listeners = append(lm.listeners, func() {
  64. defer lm.waitGroup.Done()
  65. fn()
  66. })
  67. lm.lock.Unlock()
  68. return func() {
  69. lm.waitGroup.Wait()
  70. }
  71. }
  72. func (lm *listenerManager) notifyListeners() {
  73. lm.lock.Lock()
  74. defer lm.lock.Unlock()
  75. group := threading.NewRoutineGroup()
  76. for _, listener := range lm.listeners {
  77. group.RunSafe(listener)
  78. }
  79. group.Wait()
  80. }