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  }