shutdown.go 2.0 KB

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