github.com/vnforks/kid/v5@v5.22.1-0.20200408055009-b89d99c65676/jobs/jobs.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package jobs 5 6 import ( 7 "context" 8 "time" 9 10 "net/http" 11 12 "github.com/vnforks/kid/v5/mlog" 13 "github.com/vnforks/kid/v5/model" 14 ) 15 16 const ( 17 CANCEL_WATCHER_POLLING_INTERVAL = 5000 18 ) 19 20 func (srv *JobServer) CreateJob(jobType string, jobData map[string]string) (*model.Job, *model.AppError) { 21 job := model.Job{ 22 Id: model.NewId(), 23 Type: jobType, 24 CreateAt: model.GetMillis(), 25 Status: model.JOB_STATUS_PENDING, 26 Data: jobData, 27 } 28 29 if err := job.IsValid(); err != nil { 30 return nil, err 31 } 32 33 if _, err := srv.Store.Job().Save(&job); err != nil { 34 return nil, err 35 } 36 37 return &job, nil 38 } 39 40 func (srv *JobServer) GetJob(id string) (*model.Job, *model.AppError) { 41 return srv.Store.Job().Get(id) 42 } 43 44 func (srv *JobServer) ClaimJob(job *model.Job) (bool, *model.AppError) { 45 return srv.Store.Job().UpdateStatusOptimistically(job.Id, model.JOB_STATUS_PENDING, model.JOB_STATUS_IN_PROGRESS) 46 } 47 48 func (srv *JobServer) SetJobProgress(job *model.Job, progress int64) *model.AppError { 49 job.Status = model.JOB_STATUS_IN_PROGRESS 50 job.Progress = progress 51 52 if _, err := srv.Store.Job().UpdateOptimistically(job, model.JOB_STATUS_IN_PROGRESS); err != nil { 53 return err 54 } 55 return nil 56 } 57 58 func (srv *JobServer) SetJobSuccess(job *model.Job) *model.AppError { 59 if _, err := srv.Store.Job().UpdateStatus(job.Id, model.JOB_STATUS_SUCCESS); err != nil { 60 return err 61 } 62 return nil 63 } 64 65 func (srv *JobServer) SetJobError(job *model.Job, jobError *model.AppError) *model.AppError { 66 if jobError == nil { 67 _, err := srv.Store.Job().UpdateStatus(job.Id, model.JOB_STATUS_ERROR) 68 return err 69 } 70 71 job.Status = model.JOB_STATUS_ERROR 72 job.Progress = -1 73 if job.Data == nil { 74 job.Data = make(map[string]string) 75 } 76 job.Data["error"] = jobError.Message + " — " + jobError.DetailedError 77 78 updated, err := srv.Store.Job().UpdateOptimistically(job, model.JOB_STATUS_IN_PROGRESS) 79 if err != nil { 80 return err 81 } 82 83 if !updated { 84 updated, err = srv.Store.Job().UpdateOptimistically(job, model.JOB_STATUS_CANCEL_REQUESTED) 85 if err != nil { 86 return err 87 } 88 if !updated { 89 return model.NewAppError("Jobs.SetJobError", "jobs.set_job_error.update.error", nil, "id="+job.Id, http.StatusInternalServerError) 90 } 91 } 92 93 return nil 94 } 95 96 func (srv *JobServer) SetJobCanceled(job *model.Job) *model.AppError { 97 if _, err := srv.Store.Job().UpdateStatus(job.Id, model.JOB_STATUS_CANCELED); err != nil { 98 return err 99 } 100 return nil 101 } 102 103 func (srv *JobServer) UpdateInProgressJobData(job *model.Job) *model.AppError { 104 job.Status = model.JOB_STATUS_IN_PROGRESS 105 job.LastActivityAt = model.GetMillis() 106 if _, err := srv.Store.Job().UpdateOptimistically(job, model.JOB_STATUS_IN_PROGRESS); err != nil { 107 return err 108 } 109 return nil 110 } 111 112 func (srv *JobServer) RequestCancellation(jobId string) *model.AppError { 113 updated, err := srv.Store.Job().UpdateStatusOptimistically(jobId, model.JOB_STATUS_PENDING, model.JOB_STATUS_CANCELED) 114 if err != nil { 115 return err 116 } 117 if updated { 118 return nil 119 } 120 121 updated, err = srv.Store.Job().UpdateStatusOptimistically(jobId, model.JOB_STATUS_IN_PROGRESS, model.JOB_STATUS_CANCEL_REQUESTED) 122 if err != nil { 123 return err 124 } 125 126 if updated { 127 return nil 128 } 129 130 return model.NewAppError("Jobs.RequestCancellation", "jobs.request_cancellation.status.error", nil, "id="+jobId, http.StatusInternalServerError) 131 } 132 133 func (srv *JobServer) CancellationWatcher(ctx context.Context, jobId string, cancelChan chan interface{}) { 134 for { 135 select { 136 case <-ctx.Done(): 137 mlog.Debug("CancellationWatcher for Job Aborting as job has finished.", mlog.String("job_id", jobId)) 138 return 139 case <-time.After(CANCEL_WATCHER_POLLING_INTERVAL * time.Millisecond): 140 mlog.Debug("CancellationWatcher for Job started polling.", mlog.String("job_id", jobId)) 141 if jobStatus, err := srv.Store.Job().Get(jobId); err == nil { 142 if jobStatus.Status == model.JOB_STATUS_CANCEL_REQUESTED { 143 close(cancelChan) 144 return 145 } 146 } 147 } 148 } 149 } 150 151 func GenerateNextStartDateTime(now time.Time, nextStartTime time.Time) *time.Time { 152 nextTime := time.Date(now.Year(), now.Month(), now.Day(), nextStartTime.Hour(), nextStartTime.Minute(), 0, 0, time.Local) 153 154 if !now.Before(nextTime) { 155 nextTime = nextTime.AddDate(0, 0, 1) 156 } 157 158 return &nextTime 159 } 160 161 func (srv *JobServer) CheckForPendingJobsByType(jobType string) (bool, *model.AppError) { 162 count, err := srv.Store.Job().GetCountByStatusAndType(model.JOB_STATUS_PENDING, jobType) 163 if err != nil { 164 return false, err 165 } 166 return count > 0, nil 167 } 168 169 func (srv *JobServer) GetLastSuccessfulJobByType(jobType string) (*model.Job, *model.AppError) { 170 return srv.Store.Job().GetNewestJobByStatusAndType(model.JOB_STATUS_SUCCESS, jobType) 171 }