github.com/weedge/lib@v0.0.0-20230424045628-a36dcc1d90e4/runtimer/goroutine.go (about) 1 package runtimer 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "runtime/debug" 8 "sync" 9 "time" 10 ) 11 12 // GoSafely WaitGroup wraps a `go func()` with recover() 13 func GoSafely(wg *sync.WaitGroup, ignoreRecover bool, handler func(), catchFunc func(r interface{}), w io.Writer) { 14 if w == nil { 15 w = os.Stderr 16 } 17 if wg != nil { 18 wg.Add(1) 19 } 20 go func() { 21 defer func() { 22 if r := recover(); r != nil { 23 if !ignoreRecover { 24 fmt.Fprintf(w, "%s goroutine panic: %v\n%s\n", time.Now(), r, string(debug.Stack())) 25 } 26 if catchFunc != nil { 27 if wg != nil { 28 wg.Add(1) 29 } 30 go func() { 31 defer func() { 32 if p := recover(); p != nil { 33 if !ignoreRecover { 34 fmt.Fprintf(w, "recover goroutine panic:%v\n%s\n", p, string(debug.Stack())) 35 } 36 } 37 38 if wg != nil { 39 wg.Done() 40 } 41 }() 42 catchFunc(r) 43 }() 44 } 45 } 46 if wg != nil { 47 wg.Done() 48 } 49 }() 50 handler() 51 }() 52 return 53 } 54 55 // GoUnterminated is used for which goroutine wanna long live as its process. 56 // @period: sleep time duration after panic to defeat @handle panic so frequently. if it is not positive, 57 // the @handle will be invoked asap after panic. 58 func GoUnterminated(handle func(), wg *sync.WaitGroup, ignoreRecover bool, period time.Duration, w io.Writer) { 59 GoSafely(wg, 60 ignoreRecover, 61 handle, 62 func(r interface{}) { 63 if period > 0 { 64 time.Sleep(period) 65 } 66 GoUnterminated(handle, wg, ignoreRecover, period, w) 67 }, w, 68 ) 69 return 70 }