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  }