shutdwonhook.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. package hook
  2. import (
  3. "fmt"
  4. "os"
  5. "os/signal"
  6. "reflect"
  7. "sync"
  8. "syscall"
  9. "time"
  10. )
  11. type ShutdownHook struct {
  12. hooks map[string]func(os.Signal)
  13. hooksMain func(os.Signal)
  14. mutex *sync.Mutex
  15. }
  16. var defaultHook = &ShutdownHook{ mutex: &sync.Mutex{},hooks: map[string]func(os.Signal){}}
  17. func Listen(signals ...os.Signal) {
  18. defaultHook.Listen(signals...)
  19. }
  20. func RegistryHook(name string, fn func(string)) {
  21. defaultHook.RegistryHook(name, fn)
  22. }
  23. func RegistryMainHook(fn func()) {
  24. defaultHook.RegistryMainHook(fn)
  25. }
  26. func (s *ShutdownHook) RegistryMainHook(fn func()) {
  27. s.RegistryMainHookWithParam(func(os.Signal) {
  28. fmt.Printf("[####] main shutdown process start...\n")
  29. fn()
  30. fmt.Printf("[####] main shutdown process end...\n")
  31. })
  32. }
  33. func (s *ShutdownHook) RegistryHook(name string, fn func(string)) {
  34. s.RegistryHookWithParam(name, func(os.Signal) {
  35. fmt.Printf("[####] %v shutdown process start...\n", name)
  36. fn(name)
  37. fmt.Printf("[####] %v shutdown process end...\n", name)
  38. })
  39. }
  40. func (s *ShutdownHook) RegistryHookWithParam(name string, fn func(os.Signal)) {
  41. s.mutex.Lock()
  42. defer s.mutex.Unlock()
  43. s.hooks[name] = fn
  44. }
  45. func (s *ShutdownHook) RegistryMainHookWithParam( fn func(os.Signal)) {
  46. s.hooksMain = fn
  47. }
  48. func (s *ShutdownHook) Hooks() map[string]func(os.Signal) {
  49. s.mutex.Lock()
  50. defer s.mutex.Unlock()
  51. fns := map[string]func(os.Signal){}
  52. for k, v := range s.hooks {
  53. fns[k] = v
  54. }
  55. return fns
  56. }
  57. func (s *ShutdownHook) Listen(signals ...os.Signal) {
  58. ch := make(chan os.Signal, 1)
  59. var (
  60. sig os.Signal
  61. timeGap int64
  62. )
  63. for {
  64. signal.Notify(ch, signals...)
  65. sig = <-ch
  66. target := reflect.ValueOf(sig)
  67. fmt.Println("[######] Enter End Signal... [", target.String(),"]","[", sig.String(),"]")
  68. if sig == syscall.SIGINT {
  69. timeNow := time.Now().UnixNano()
  70. if timeNow < timeGap+(1000*int64(time.Millisecond)) {
  71. break
  72. }
  73. timeGap = time.Now().UnixNano()
  74. } else if sig == syscall.SIGTERM || sig == syscall.SIGKILL || sig == syscall.SIGQUIT { // Delete syscall.SIGHUP
  75. break
  76. }
  77. }
  78. fmt.Println("[######] shutdown process start... ", sig.String())
  79. // SUB HOOK PROCESS
  80. var wg sync.WaitGroup
  81. for _, fn := range s.Hooks() {
  82. wg.Add(1)
  83. go func(sig os.Signal, fn func(os.Signal)) {
  84. defer wg.Done()
  85. fn(sig)
  86. }(sig, fn)
  87. }
  88. wg.Wait()
  89. // MAIN HOOK PROCESS
  90. if s.hooksMain != nil {
  91. wg.Add(1)
  92. go func(sig os.Signal, fn func(os.Signal)) {
  93. defer wg.Done()
  94. fn(sig)
  95. }(sig, s.hooksMain)
  96. }
  97. wg.Wait()
  98. fmt.Println("[######] shutdown process complete...")
  99. }