github.com/weedge/lib@v0.0.0-20230424045628-a36dcc1d90e4/pool/workerpool/worker.go (about) 1 package workerpool 2 3 import ( 4 "github.com/weedge/lib/runtimer" 5 "github.com/weedge/lib/strings" 6 "runtime" 7 "runtime/debug" 8 "sync/atomic" 9 "time" 10 11 "github.com/weedge/lib/log" 12 ) 13 14 type Worker struct { 15 timer *time.Timer 16 myWorkerPool *WorkerPool //所属任务工作池 17 hasGoroutineRunning int32 //是否有对应的goroutine在运行 18 chTaskIsTimeOut chan<- bool //任务是否超时,true 超时,false 正常 由添加任务时创建 19 chExecuteGoroutineOut chan int //执行任务的goroutine结束 -> worker goroutine 结束 20 } 21 22 func newWorker(wp *WorkerPool) *Worker { 23 return &Worker{ 24 timer: time.NewTimer(DefaultTimeOut), 25 myWorkerPool: wp, 26 chExecuteGoroutineOut: make(chan int, 1), 27 } 28 } 29 30 func (worker *Worker) safelyDo() { 31 if nil == worker.myWorkerPool { 32 log.Error("myWorkerPool ptr is nil ") 33 return 34 } 35 36 debug.SetPanicOnFault(true) 37 defer worker.myWorkerPool.wg.Done() 38 defer func() { 39 if r := recover(); r != nil { 40 if worker.myWorkerPool.isWorking() { 41 worker.myWorkerPool.chAddWorker <- 1 42 } 43 44 atomic.AddInt32(&(worker.myWorkerPool.curWorkerNum), -1) 45 atomic.SwapInt32(&(worker.hasGoroutineRunning), 0) 46 log.Error("check timeout worker goroutine is crash, panic", r, strings.BytesToString(debug.Stack())) 47 } 48 }() 49 50 worker.execute() 51 } 52 53 func (worker *Worker) execute() { 54 for { 55 select { 56 case task, ok := <-worker.myWorkerPool.chWorkTask: 57 if ok { 58 if task.TimeOut > 0 { 59 worker.timer.Reset(task.TimeOut) 60 } 61 taskDoResCh := make(chan bool, 1) 62 63 runtimer.GoSafely(nil, false, func() { 64 taskDoResCh <- task.Do(task.InParam, task.OutParam) 65 }, nil, nil) 66 67 select { 68 case <-worker.timer.C: 69 if task.ChIsTimeOut != nil { 70 task.ChIsTimeOut <- true 71 } 72 if task.OnTimeOut != nil { 73 task.OnTimeOut(task.InParam, task.OutParam) 74 } 75 case _, ok := <-taskDoResCh: 76 if ok && task.ChIsTimeOut != nil { 77 task.ChIsTimeOut <- false 78 } 79 } 80 81 worker.destroyAfterTaskDone() 82 } else { 83 worker.myWorkerPool.close() 84 log.Info("close chWorkTask, myWorkerPool close and exit worker goroutine, the current goroutine number:", atomic.LoadInt32(&worker.myWorkerPool.curWorkerNum)) 85 runtime.Goexit() 86 } 87 case _, ok := <-worker.chExecuteGoroutineOut: 88 if worker.myWorkerPool.isWorking() && atomic.LoadInt32(&worker.hasGoroutineRunning) <= 0 && ok { 89 log.Info("send to add worker when ExecuteGoroutineOut") 90 worker.myWorkerPool.chAddWorker <- 1 91 } 92 atomic.AddInt32(&(worker.myWorkerPool.curWorkerNum), -1) 93 log.Info(" exit this execute worker goroutine, the current goroutine number:", atomic.LoadInt32(&worker.myWorkerPool.curWorkerNum)) 94 runtime.Goexit() 95 } 96 } 97 } 98 99 // worker destroy after task done cond: 100 // 1. worker pool is working 101 // 2. work task ch is empty 102 // 3. cur worker num of pool > min worker num 103 // 4. (now - add worker last time) > worker life time 104 func (worker *Worker) destroyAfterTaskDone() { 105 chWorkTaskLen := len(worker.myWorkerPool.chWorkTask) 106 if worker.myWorkerPool.isWorking() && chWorkTaskLen <= 0 && 107 atomic.LoadInt32(&worker.myWorkerPool.curWorkerNum) > worker.myWorkerPool.minWorkerNum && 108 time.Now().Unix()-worker.myWorkerPool.addWorkerLastTime >= workerGoroutineLifeTime { 109 worker.chExecuteGoroutineOut <- 1 110 log.Info("exit more worker goroutine, the current goroutine number:", atomic.LoadInt32(&worker.myWorkerPool.curWorkerNum)) 111 runtime.Goexit() 112 } 113 }