github.com/songzhibin97/gkit@v1.2.13/distributed/worker.go (about) 1 package distributed 2 3 import ( 4 "fmt" 5 "os" 6 "os/signal" 7 "sync" 8 "syscall" 9 "time" 10 11 "github.com/songzhibin97/gkit/distributed/retry" 12 13 "github.com/pkg/errors" 14 15 "github.com/songzhibin97/gkit/distributed/task" 16 ) 17 18 var ( 19 ErrWorkerGracefullyQuit = errors.New("worker quit gracefully") 20 ErrWorkerAbruptlyQuit = errors.New("worker quit abruptly") 21 ) 22 23 // Worker 任务处理 24 type Worker struct { 25 NoUnixSignals bool `json:"no_unix_signals"` // 是否使用unix信号控制 26 bindService *Server 27 Concurrency int `json:"concurrency"` // 并发数 28 ConsumerTag string `json:"consumer_tag"` // 消费者标签 29 Queue string `json:"queue"` // 队列名称 30 errorHandler func(err error) // 错误处理 31 beforeTaskHandler func(task *task.Signature) // 在任务执行前执行 32 afterTaskHandler func(task *task.Signature) // 在任务结束后执行 33 preConsumeHandler func(worker *Worker) bool // 判断是否需要预处理 34 } 35 36 // SetErrorHandler 设置处理错误函数 37 func (w *Worker) SetErrorHandler(f func(err error)) { 38 w.errorHandler = f 39 } 40 41 // SetBeforeTaskHandler 设置执行任务前执行函数 42 func (w *Worker) SetBeforeTaskHandler(f func(task *task.Signature)) { 43 w.beforeTaskHandler = f 44 } 45 46 // SetAfterTaskHandler 设置执行任务后执行函数 47 func (w *Worker) SetAfterTaskHandler(f func(task *task.Signature)) { 48 w.afterTaskHandler = f 49 } 50 51 // SetPreConsumeHandler 设置预处理函数 52 func (w *Worker) SetPreConsumeHandler(f func(worker *Worker) bool) { 53 w.preConsumeHandler = f 54 } 55 56 // Quit 触发强制退出 57 func (w *Worker) Quit() { 58 w.bindService.GetController().StopConsuming() 59 } 60 61 // Process 任务处理 62 func (w *Worker) Process(signature *task.Signature) error { 63 // 如果任务没有注册,快速返回 64 if !w.bindService.IsRegisteredTask(signature.Name) { 65 return nil 66 } 67 // 获取注册执行任务的函数 68 handler, ok := w.bindService.GetRegisteredTask(signature.Name) 69 if !ok { 70 return nil 71 } 72 // 设置任务状态,改为接收状态 73 if err := w.bindService.GetBackend().SetStateReceived(signature); err != nil { 74 return errors.Wrap(err, "worker set task state to 'received' error, signature id:"+signature.ID) 75 } 76 exec, err := task.NewTaskWithSignature(handler, signature) 77 if err != nil { 78 _ = w.handlerFailed(signature, err) 79 return err 80 } 81 82 // 设置任务状态,改为开始执行 83 if err = w.bindService.GetBackend().SetStateStarted(signature); err != nil { 84 return errors.Wrap(err, "worker set task state to 'started' error, signature id:"+signature.ID) 85 } 86 87 // 生命周期前执行 88 if w.beforeTaskHandler != nil { 89 w.beforeTaskHandler(signature) 90 } 91 // 生命周期后执行,注册defer 92 if w.afterTaskHandler != nil { 93 defer w.afterTaskHandler(signature) 94 } 95 // 任务调用 96 results, err := exec.Call() 97 if err != nil { 98 // 判断err是否是可重试错误 99 retryErr, ok := (interface{})(err).(task.ErrRetryTaskLater) 100 if ok { 101 // 重试 102 return w.handlerRetryIn(signature, retryErr.RetryIn()) 103 } 104 // 根据自定义重试次数开始重试 105 if signature.RetryCount > 0 { 106 return w.handlerRetry(signature) 107 } 108 // 置为失败 109 return w.handlerFailed(signature, err) 110 } 111 // 任务完成 112 return w.handlerSucceeded(signature, results) 113 } 114 115 // handlerRetry 处理程序重试 116 func (w *Worker) handlerRetry(signature *task.Signature) error { 117 // 设置重试状态 118 if err := w.bindService.GetBackend().SetStateRetry(signature); err != nil { 119 return errors.Wrap(err, "worker set task state to 'retry' error, signature id:"+signature.ID) 120 } 121 signature.RetryCount-- 122 123 // 获取间隔时间 124 signature.RetryInterval = retry.FibonacciNext(signature.RetryInterval) 125 126 eta := time.Now().Add(time.Second * time.Duration(signature.RetryInterval)) 127 signature.ETA = &eta 128 w.bindService.helper.Warnf("Task %s failed. Going to retry in %d seconds.", signature.ID, signature.RetryInterval) 129 _, err := w.bindService.SendTask(signature) 130 return err 131 } 132 133 // handlerRetry 处理指定错误程序重试 134 func (w *Worker) handlerRetryIn(signature *task.Signature, retryIn time.Duration) error { 135 // 设置重试状态 136 if err := w.bindService.GetBackend().SetStateRetry(signature); err != nil { 137 return errors.Wrap(err, "worker set task state to 'retry' error, signature id:"+signature.ID) 138 } 139 eta := time.Now().Add(retryIn) 140 signature.ETA = &eta 141 w.bindService.helper.Warnf("Task %s failed. Going to retry in %.0f seconds.", signature.ID, retryIn.Seconds()) 142 _, err := w.bindService.SendTask(signature) 143 return err 144 } 145 146 // handlerSucceeded 处理程序成功状态 147 func (w *Worker) handlerSucceeded(signature *task.Signature, results []*task.Result) error { 148 if err := w.bindService.GetBackend().SetStateSuccess(signature, results); err != nil { 149 return errors.Wrap(err, "worker set task state to 'succeeded' error, signature id:"+signature.ID) 150 } 151 152 // 执行任务成功回调 153 for _, success := range signature.CallbackOnSuccess { 154 for _, result := range results { 155 success.Args = append(success.Args, 156 task.Arg{ 157 Type: result.Type, 158 Value: result.Value, 159 }, 160 ) 161 } 162 _, _ = w.bindService.SendTask(success) 163 } 164 165 // 如果没有回调,完成 166 if signature.CallbackChord == nil { 167 return nil 168 } 169 170 // 不是任务组,完成 171 if signature.GroupID == "" { 172 return nil 173 } 174 175 // 检查组内任务是否完成 176 groupCompleted, err := w.bindService.GetBackend().GroupCompleted(signature.GroupID) 177 if err != nil { 178 return errors.Wrap(err, "group completed id:"+signature.ID+"group id:"+signature.GroupID) 179 } 180 // 不是组内最后一个任务 181 if !groupCompleted { 182 return nil 183 } 184 185 // 调用组回调 186 call, err := w.bindService.GetBackend().TriggerCompleted(signature.GroupID) 187 if err != nil { 188 return fmt.Errorf("TriggerCompleted group %s returned error: %s", signature.GroupID, err) 189 } 190 191 if !call { 192 // 已经调用过了 193 return nil 194 } 195 196 // 获取组任务状态 197 taskStatus, err := w.bindService.GetBackend().GroupTaskStatus(signature.GroupID) 198 if err != nil { 199 w.bindService.helper.Errorf( 200 "Failed to get tasks states for group:[%s]. Task count:[%d]. The chord may not be triggered. Error:[%s]", 201 signature.ID, 202 signature.GroupTaskCount, 203 err, 204 ) 205 return nil 206 } 207 // 遍历任务状态 208 for _, status := range taskStatus { 209 if !status.IsSuccess() { 210 // 如果有未成功的任务,组任务失败 211 return nil 212 } 213 for _, result := range status.Results { 214 signature.CallbackChord.Args = append(signature.CallbackChord.Args, 215 task.Arg{Type: result.Type, Value: result.Value}) 216 } 217 } 218 _, err = w.bindService.SendTask(signature.CallbackChord) 219 return err 220 } 221 222 // handlerFailed 处理任务失败状态 223 func (w *Worker) handlerFailed(signature *task.Signature, err error) error { 224 if err := w.bindService.GetBackend().SetStateFailure(signature, err.Error()); err != nil { 225 return errors.Wrap(err, "worker set task state to 'succeeded' error, signature id:"+signature.ID) 226 } 227 if w.errorHandler != nil { 228 w.errorHandler(err) 229 } else { 230 w.bindService.helper.Errorf("Failed processing task %s. Error = %v", signature.ID, err) 231 } 232 for _, _error := range signature.CallbackOnError { 233 _error.Args = append([]task.Arg{{Type: "string", Value: err.Error()}}, _error.Args...) 234 _, _ = w.bindService.SendTask(_error) 235 } 236 if signature.StopTaskDeletionOnError { 237 return errors.New("StopTaskDeletionOnError") 238 } 239 return nil 240 } 241 242 func (w *Worker) ConsumeQueue() string { 243 return w.Queue 244 } 245 246 func (w *Worker) PreConsumeHandler() bool { 247 if w.preConsumeHandler != nil { 248 return true 249 } 250 return w.preConsumeHandler(w) 251 } 252 253 // Start 启动 254 func (w *Worker) Start() error { 255 errChan := make(chan error, 1) 256 w.StartSync(errChan) 257 return <-errChan 258 } 259 260 // StartSync 异步启动 261 func (w *Worker) StartSync(errChan chan<- error) { 262 w.bindService.helper.Info("worker start") 263 w.bindService.helper.Info("worker tag", w.ConsumerTag) 264 w.bindService.helper.Info("use queue", w.Queue) 265 controller := w.bindService.GetController() 266 267 var wg sync.WaitGroup 268 go func() { 269 for { 270 retry, err := controller.StartConsuming(w.Concurrency, w) 271 if retry { 272 if w.errorHandler != nil { 273 w.errorHandler(err) 274 } else { 275 w.bindService.helper.Warnf("controller consume err: %s", err) 276 } 277 } else { 278 wg.Wait() 279 errChan <- err 280 return 281 } 282 } 283 }() 284 if !w.NoUnixSignals { 285 sign := make(chan os.Signal, 1) 286 signal.Notify(sign, os.Interrupt, syscall.SIGTERM) 287 288 var acceptCount uint 289 go func() { 290 for s := range sign { 291 w.bindService.helper.Warnf("signal received: %v", s) 292 acceptCount++ 293 if acceptCount < 2 { 294 // 正常退出 295 w.bindService.helper.Warn("Waiting for running tasks to finish before shutting down") 296 wg.Add(1) 297 go func() { 298 w.Quit() 299 errChan <- ErrWorkerGracefullyQuit 300 wg.Done() 301 }() 302 } else { 303 // 重复收到退出信号 304 errChan <- ErrWorkerAbruptlyQuit 305 } 306 } 307 }() 308 } 309 }