shutdown.go 1.9 KB

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