shutdown.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  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. func AddShutdownListener(fn func()) (waitForCalled func()) {
  22. return shutdownListeners.addListener(fn)
  23. }
  24. func AddWrapUpListener(fn func()) (waitForCalled func()) {
  25. return wrapUpListeners.addListener(fn)
  26. }
  27. func SetTimeToForceQuit(duration time.Duration) {
  28. delayTimeBeforeForceQuit = duration
  29. }
  30. func gracefulStop(signals chan os.Signal) {
  31. signal.Stop(signals)
  32. logx.Info("Got signal SIGTERM, shutting down...")
  33. wrapUpListeners.notifyListeners()
  34. time.Sleep(wrapUpTime)
  35. shutdownListeners.notifyListeners()
  36. time.Sleep(delayTimeBeforeForceQuit - wrapUpTime)
  37. logx.Infof("Still alive after %v, going to force kill the process...", delayTimeBeforeForceQuit)
  38. syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
  39. }
  40. type listenerManager struct {
  41. lock sync.Mutex
  42. waitGroup sync.WaitGroup
  43. listeners []func()
  44. }
  45. func (lm *listenerManager) addListener(fn func()) (waitForCalled func()) {
  46. lm.waitGroup.Add(1)
  47. lm.lock.Lock()
  48. lm.listeners = append(lm.listeners, func() {
  49. defer lm.waitGroup.Done()
  50. fn()
  51. })
  52. lm.lock.Unlock()
  53. return func() {
  54. lm.waitGroup.Wait()
  55. }
  56. }
  57. func (lm *listenerManager) notifyListeners() {
  58. lm.lock.Lock()
  59. defer lm.lock.Unlock()
  60. for _, listener := range lm.listeners {
  61. listener()
  62. }
  63. }