package util import ( "dsbqj-admin/pkg/logger" "fmt" "log" "os" "os/signal" "runtime/debug" "sync/atomic" "syscall" "time" ) var ( gonum int64 = 0 //主协程数管理 goState int64 = 0 //游戏服运行状态 0运行中 1需要安全结束协程 needAlarm = true //需要发送告警信息 ) // 所有协程是否安全运行 func IsGoRuntime() bool { return atomic.LoadInt64(&goState) == 0 } // go协程安全结束 func GoSecurityOver() { atomic.StoreInt64(&goState, 1) } // 开启一个主要协程 mark协程标识 func StartGo(mark string, f func(), overf func(isdebug bool)) { startGo(mark, true, f, overf) } // 次要go // mark标识 // f 主要逻辑方法 // overf 结束方法 func StartMinorGO(mark string, f func(), overf func(isdebug bool)) { startGo(mark, false, f, overf) } // 开始go // mark 标识 // ismain 是否主要协程(结束是否影响整体业务) // f 主要方法 // overf 结束方法 func startGo(mark string, ismain bool, f func(), overf func(isdebug bool)) { if f == nil { log.Panicln("start version fail:" + mark + ", f is nil") } if ismain { atomic.AddInt64(&gonum, 1) } go func() { logger.Info("start go: %s, ismain: %t", mark, ismain) if ismain { log.Println("start go:", mark) } defer func() { isdebug := false if err := recover(); err != nil { logger.Debug(fmt.Sprint("[debug] ", mark, " error:", err, " stack:", string(debug.Stack()))) isdebug = true } if ismain { log.Println("end go:", mark, ",isdebug:", isdebug) } logger.Info("version over mark: %v ,ismain: %t", mark, ismain) if overf != nil { func() { //防止结束任务debug defer func() { ListenDebug(mark + " overf bug") }() overf(isdebug) }() } if ismain { //需要安全结束协程 atomic.AddInt64(&gonum, -1) GoSecurityOver() } }() f() }() } // 监听debug(true为有bug) func ListenDebug(mark string) bool { if err := recover(); err != nil { logger.Debug("[debug] %s error: %s stack: %s", mark, err, string(debug.Stack())) return true } return false } // 监控所有主要协程,都结束后,才结束 // stopall 程序被kill后执行 func ListenAllGO(stopall func(), alarmGroup string, alarmContent string) { ListenKill() flag := false for { time.Sleep(2 * time.Second) if !flag && !IsGoRuntime() { //监听有协程关闭,主动停止需要手动停止的协程 flag = true if stopall != nil { stopall() } log.Println("stopall goruntime") } v := atomic.LoadInt64(&gonum) if v <= 0 { if needAlarm { // 发送报警 //SendAlarm(alarmGroup, alarmContent) } logger.Info("meeting over") log.Println("all go over") return } } } // 监听kill命令 func ListenKill() { StartMinorGO("listen kill", func() { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, os.Kill) signal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) s := <-c needAlarm = false logger.Info("Server Exit: %s", s.String()) atomic.StoreInt64(&goState, 1) //提示监听协程结束 }, nil) }