gproc_signal.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package gproc
  7. import (
  8. "context"
  9. "os"
  10. "os/signal"
  11. "sync"
  12. "syscall"
  13. "github.com/gogf/gf/v2/internal/intlog"
  14. "github.com/gogf/gf/v2/util/gutil"
  15. )
  16. // SigHandler defines a function type for signal handling.
  17. type SigHandler func(sig os.Signal)
  18. var (
  19. // Use internal variable to guarantee concurrent safety
  20. // when multiple Listen happen.
  21. signalChan = make(chan os.Signal, 1)
  22. signalHandlerMu sync.Mutex
  23. signalHandlerMap = make(map[os.Signal][]SigHandler)
  24. shutdownSignalMap = map[os.Signal]struct{}{
  25. syscall.SIGINT: {},
  26. syscall.SIGQUIT: {},
  27. syscall.SIGKILL: {},
  28. syscall.SIGTERM: {},
  29. syscall.SIGABRT: {},
  30. }
  31. )
  32. func init() {
  33. for sig := range shutdownSignalMap {
  34. signalHandlerMap[sig] = make([]SigHandler, 0)
  35. }
  36. }
  37. // AddSigHandler adds custom signal handler for custom one or more signals.
  38. func AddSigHandler(handler SigHandler, signals ...os.Signal) {
  39. signalHandlerMu.Lock()
  40. defer signalHandlerMu.Unlock()
  41. for _, sig := range signals {
  42. signalHandlerMap[sig] = append(signalHandlerMap[sig], handler)
  43. }
  44. }
  45. // AddSigHandlerShutdown adds custom signal handler for shutdown signals:
  46. // syscall.SIGINT,
  47. // syscall.SIGQUIT,
  48. // syscall.SIGKILL,
  49. // syscall.SIGTERM,
  50. // syscall.SIGABRT.
  51. func AddSigHandlerShutdown(handler ...SigHandler) {
  52. signalHandlerMu.Lock()
  53. defer signalHandlerMu.Unlock()
  54. for _, h := range handler {
  55. for sig := range shutdownSignalMap {
  56. signalHandlerMap[sig] = append(signalHandlerMap[sig], h)
  57. }
  58. }
  59. }
  60. // Listen blocks and does signal listening and handling.
  61. func Listen() {
  62. var (
  63. signals = getHandlerSignals()
  64. ctx = context.Background()
  65. wg = sync.WaitGroup{}
  66. sig os.Signal
  67. )
  68. signal.Notify(signalChan, signals...)
  69. for {
  70. sig = <-signalChan
  71. intlog.Printf(ctx, `signal received: %s`, sig.String())
  72. if handlers := getHandlersBySignal(sig); len(handlers) > 0 {
  73. for _, handler := range handlers {
  74. wg.Add(1)
  75. var (
  76. currentHandler = handler
  77. currentSig = sig
  78. )
  79. gutil.TryCatch(ctx, func(ctx context.Context) {
  80. defer wg.Done()
  81. currentHandler(currentSig)
  82. }, func(ctx context.Context, exception error) {
  83. intlog.Errorf(ctx, `execute signal handler failed: %+v`, exception)
  84. })
  85. }
  86. }
  87. // If it is shutdown signal, it exits this signal listening.
  88. if _, ok := shutdownSignalMap[sig]; ok {
  89. intlog.Printf(
  90. ctx,
  91. `receive shutdown signal "%s", waiting all signal handler done`,
  92. sig.String(),
  93. )
  94. // Wait until signal handlers done.
  95. wg.Wait()
  96. intlog.Print(ctx, `all signal handler done, exit process`)
  97. return
  98. }
  99. }
  100. }
  101. func getHandlerSignals() []os.Signal {
  102. signalHandlerMu.Lock()
  103. defer signalHandlerMu.Unlock()
  104. var signals = make([]os.Signal, 0)
  105. for s := range signalHandlerMap {
  106. signals = append(signals, s)
  107. }
  108. return signals
  109. }
  110. func getHandlersBySignal(sig os.Signal) []SigHandler {
  111. signalHandlerMu.Lock()
  112. defer signalHandlerMu.Unlock()
  113. return signalHandlerMap[sig]
  114. }