gitee.com/h79/goutils@v1.22.10/common/scheduler/job.go (about) 1 package scheduler 2 3 import ( 4 "fmt" 5 "gitee.com/h79/goutils/common/option" 6 "gitee.com/h79/goutils/common/system" 7 "time" 8 ) 9 10 const ( 11 QuitExecMustFlag = 1 //退出时,也执行一下 12 ) 13 14 type ProcessHandler interface { 15 ProcessJob(job *Job, opts ...option.Option) (interface{}, error) 16 } 17 18 var _ ProcessHandler = (HandlerFunc)(nil) 19 20 type HandlerFunc func(job *Job, opts ...option.Option) (interface{}, error) 21 22 func (fn HandlerFunc) ProcessJob(job *Job, opts ...option.Option) (interface{}, error) { 23 return fn(job, opts...) 24 } 25 26 type ResultHandler interface { 27 ResultJob(res *Result, opts ...option.Option) 28 } 29 30 var _ ResultHandler = (ResultFunc)(nil) 31 32 type ResultFunc func(res *Result, opts ...option.Option) 33 34 func (fn ResultFunc) ResultJob(res *Result, opts ...option.Option) { 35 fn(res, opts...) 36 } 37 38 var _ Task = (*Job)(nil) 39 40 type Job struct { 41 Id string 42 Type string 43 TraceId string 44 State State 45 MustFlag int32 // QuitExecMustFlag quit时,要不要被执行,默认不执行 46 Delay time.Duration // 延后执行,卡住 47 Timeout time.Duration // 超时 48 execAt int64 49 startAt int64 50 count int64 // execute count 51 payload any // 自定认数据 52 processHandler ProcessHandler 53 resultHandler ResultHandler 54 } 55 56 type Result struct { 57 TraceId string `json:"traceId"` 58 Type string `json:"type"` 59 Id string `json:"id"` 60 Err error `json:"err,omitempty"` 61 Data any `json:"data,omitempty"` //处理结果 62 } 63 64 type shellData struct { 65 Cmd string 66 } 67 68 func NewShellJob(cmd string) *Job { 69 job := NewJob("shell", fmt.Sprintf("ShellJob:Cmd:%s", cmd), 0) 70 job.WithPayload(&shellData{Cmd: cmd}) 71 job.WithHandlerFunc(func(j *Job, opts ...option.Option) (interface{}, error) { 72 var payload = j.GetPayload() 73 shell, ok := payload.(*shellData) 74 if !ok { 75 return nil, fmt.Errorf("payload not shelldata") 76 } 77 var res = system.SyncExec(shell.Cmd, job.Timeout) 78 return res, nil 79 }) 80 return job 81 } 82 83 func BuildJob(jobType, jobId string, timeout time.Duration) Job { 84 return Job{ 85 Type: jobType, 86 Id: jobId, 87 State: InitState, 88 startAt: time.Now().Local().UnixMilli(), 89 Timeout: timeout, 90 } 91 } 92 93 func NewJob(jobType, jobId string, timeout time.Duration) *Job { 94 job := BuildJob(jobType, jobId, timeout) 95 return &job 96 } 97 98 func NewEmptyJob(fn HandlerFunc) *Job { 99 job := BuildJob("", "", 0) 100 return job.SetHandler(fn) 101 } 102 103 func (job *Job) SetHandler(fn ProcessHandler) *Job { 104 job.processHandler = fn 105 return job 106 } 107 108 func (job *Job) WithHandlerFunc(fn func(job *Job, opts ...option.Option) (interface{}, error)) *Job { 109 return job.SetHandler(HandlerFunc(fn)) 110 } 111 112 func (job *Job) SetResultHandler(fn ResultHandler) *Job { 113 job.resultHandler = fn 114 return job 115 } 116 117 func (job *Job) WithResultFunc(fn func(res *Result, opts ...option.Option)) *Job { 118 return job.SetResultHandler(ResultFunc(fn)) 119 } 120 121 func (job *Job) WithMustFlag(m int32) *Job { 122 job.MustFlag = m 123 return job 124 } 125 126 func (job *Job) WithTimeOut(timeout time.Duration) *Job { 127 job.Timeout = timeout 128 return job 129 } 130 131 func (job *Job) WithTraceId(traceId string) *Job { 132 job.TraceId = traceId 133 return job 134 } 135 136 func (job *Job) WithDelay(delay time.Duration) *Job { 137 job.Delay = delay 138 return job 139 } 140 141 func (job *Job) WithPayload(payload interface{}) *Job { 142 job.payload = payload 143 return job 144 } 145 146 func (job *Job) GetType() string { 147 return job.Type 148 } 149 150 func (job *Job) GetId() string { 151 return job.Id 152 } 153 154 func (job *Job) GetState() State { 155 return job.State 156 } 157 158 func (job *Job) GetPayload() any { 159 return job.payload 160 } 161 func (job *Job) SetPayload(payload any) { 162 job.payload = payload 163 } 164 165 func (job *Job) GetExecAt() int64 { 166 return job.execAt 167 } 168 169 func (job *Job) GetCount() int64 { 170 return job.count 171 } 172 173 func (job *Job) GetStartAt() int64 { 174 return job.startAt 175 } 176 177 func (job *Job) Execute(opts ...option.Option) (interface{}, error) { 178 if job.State.IsQuit() { 179 return nil, ErrJobQuited 180 } 181 if job.processHandler == nil { 182 job.State = CompletedState 183 return nil, ErrJobFuncNil 184 } 185 quited := option.Select(QuitedOpt, false, opts...) 186 stop := option.Select(StopOpt, false, opts...) 187 if job.MustFlag&QuitExecMustFlag == 0 { 188 if quited { 189 return nil, ErrJobQuited 190 } 191 if stop { 192 return nil, ErrJobStop 193 } 194 } 195 timeout := job.Timeout 196 delay := job.Delay 197 if quited || stop { 198 timeout = 0 199 delay = 0 200 } 201 if job.State == InitState { 202 job.State = RunningState 203 if delay > 0 { 204 system.Wait(delay) 205 } 206 } 207 job.count++ 208 return system.RunAfter(timeout, func(opts ...option.Option) (any, error) { 209 res, err := job.processHandler.ProcessJob(job, opts...) 210 if job.resultHandler != nil { 211 job.resultHandler.ResultJob(job.NewResult(res, err)) 212 } 213 return res, err 214 }, opts...) 215 } 216 217 func (job *Job) Cancel() { 218 job.State = CancelState 219 } 220 221 func (job *Job) Pause() { 222 job.State = PauseState 223 } 224 225 func (job *Job) Start() { 226 job.State = RunningState 227 } 228 229 func (job *Job) IsQuit() bool { 230 return job.State.IsQuit() 231 } 232 233 func (job *Job) CheckTimeout() bool { 234 if job.Timeout <= 0 { 235 return false 236 } 237 now := time.Now().Local().UnixMilli() 238 if job.startAt <= 0 { 239 job.startAt = now 240 } 241 return now-job.startAt > job.Timeout.Milliseconds() 242 } 243 244 func (job *Job) NewResult(data any, err error) *Result { 245 return &Result{TraceId: job.TraceId, Type: job.Type, Id: job.Id, Data: data, Err: err} 246 }