gomgr.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package util
  2. import (
  3. "dsbqj-admin/pkg/logger"
  4. "fmt"
  5. "log"
  6. "os"
  7. "os/signal"
  8. "runtime/debug"
  9. "sync/atomic"
  10. "syscall"
  11. "time"
  12. )
  13. var (
  14. gonum int64 = 0 //主协程数管理
  15. goState int64 = 0 //游戏服运行状态 0运行中 1需要安全结束协程
  16. needAlarm = true //需要发送告警信息
  17. )
  18. // 所有协程是否安全运行
  19. func IsGoRuntime() bool {
  20. return atomic.LoadInt64(&goState) == 0
  21. }
  22. // go协程安全结束
  23. func GoSecurityOver() {
  24. atomic.StoreInt64(&goState, 1)
  25. }
  26. // 开启一个主要协程 mark协程标识
  27. func StartGo(mark string, f func(), overf func(isdebug bool)) {
  28. startGo(mark, true, f, overf)
  29. }
  30. // 次要go
  31. // mark标识
  32. // f 主要逻辑方法
  33. // overf 结束方法
  34. func StartMinorGO(mark string, f func(), overf func(isdebug bool)) {
  35. startGo(mark, false, f, overf)
  36. }
  37. // 开始go
  38. // mark 标识
  39. // ismain 是否主要协程(结束是否影响整体业务)
  40. // f 主要方法
  41. // overf 结束方法
  42. func startGo(mark string, ismain bool, f func(), overf func(isdebug bool)) {
  43. if f == nil {
  44. log.Panicln("start version fail:" + mark + ", f is nil")
  45. }
  46. if ismain {
  47. atomic.AddInt64(&gonum, 1)
  48. }
  49. go func() {
  50. logger.Info("start go: %s, ismain: %t", mark, ismain)
  51. if ismain {
  52. log.Println("start go:", mark)
  53. }
  54. defer func() {
  55. isdebug := false
  56. if err := recover(); err != nil {
  57. logger.Debug(fmt.Sprint("[debug] ", mark, " error:", err, " stack:", string(debug.Stack())))
  58. isdebug = true
  59. }
  60. if ismain {
  61. log.Println("end go:", mark, ",isdebug:", isdebug)
  62. }
  63. logger.Info("version over mark: %v ,ismain: %t", mark, ismain)
  64. if overf != nil {
  65. func() { //防止结束任务debug
  66. defer func() {
  67. ListenDebug(mark + " overf bug")
  68. }()
  69. overf(isdebug)
  70. }()
  71. }
  72. if ismain { //需要安全结束协程
  73. atomic.AddInt64(&gonum, -1)
  74. GoSecurityOver()
  75. }
  76. }()
  77. f()
  78. }()
  79. }
  80. // 监听debug(true为有bug)
  81. func ListenDebug(mark string) bool {
  82. if err := recover(); err != nil {
  83. logger.Debug("[debug] %s error: %s stack: %s", mark, err, string(debug.Stack()))
  84. return true
  85. }
  86. return false
  87. }
  88. // 监控所有主要协程,都结束后,才结束
  89. // stopall 程序被kill后执行
  90. func ListenAllGO(stopall func(), alarmGroup string, alarmContent string) {
  91. ListenKill()
  92. flag := false
  93. for {
  94. time.Sleep(2 * time.Second)
  95. if !flag && !IsGoRuntime() { //监听有协程关闭,主动停止需要手动停止的协程
  96. flag = true
  97. if stopall != nil {
  98. stopall()
  99. }
  100. log.Println("stopall goruntime")
  101. }
  102. v := atomic.LoadInt64(&gonum)
  103. if v <= 0 {
  104. if needAlarm {
  105. // 发送报警
  106. //SendAlarm(alarmGroup, alarmContent)
  107. }
  108. logger.Info("meeting over")
  109. log.Println("all go over")
  110. return
  111. }
  112. }
  113. }
  114. // 监听kill命令
  115. func ListenKill() {
  116. StartMinorGO("listen kill", func() {
  117. c := make(chan os.Signal, 1)
  118. signal.Notify(c, os.Interrupt, os.Kill)
  119. signal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
  120. s := <-c
  121. needAlarm = false
  122. logger.Info("Server Exit: %s", s.String())
  123. atomic.StoreInt64(&goState, 1) //提示监听协程结束
  124. }, nil)
  125. }