github.com/dschalla/mattermost-server@v4.8.1-rc1+incompatible/jobs/jobs.go (about)

     1  // Copyright (c) 2017-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  	l4g "github.com/alecthomas/log4go"
    13  	"github.com/mattermost/mattermost-server/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 result := <-srv.Store.Job().Save(&job); result.Err != nil {
    34  		return nil, result.Err
    35  	}
    36  
    37  	return &job, nil
    38  }
    39  
    40  func (srv *JobServer) GetJob(id string) (*model.Job, *model.AppError) {
    41  	if result := <-srv.Store.Job().Get(id); result.Err != nil {
    42  		return nil, result.Err
    43  	} else {
    44  		return result.Data.(*model.Job), nil
    45  	}
    46  }
    47  
    48  func (srv *JobServer) ClaimJob(job *model.Job) (bool, *model.AppError) {
    49  	if result := <-srv.Store.Job().UpdateStatusOptimistically(job.Id, model.JOB_STATUS_PENDING, model.JOB_STATUS_IN_PROGRESS); result.Err != nil {
    50  		return false, result.Err
    51  	} else {
    52  		success := result.Data.(bool)
    53  		return success, nil
    54  	}
    55  }
    56  
    57  func (srv *JobServer) SetJobProgress(job *model.Job, progress int64) *model.AppError {
    58  	job.Status = model.JOB_STATUS_IN_PROGRESS
    59  	job.Progress = progress
    60  
    61  	if result := <-srv.Store.Job().UpdateOptimistically(job, model.JOB_STATUS_IN_PROGRESS); result.Err != nil {
    62  		return result.Err
    63  	} else {
    64  		return nil
    65  	}
    66  }
    67  
    68  func (srv *JobServer) SetJobSuccess(job *model.Job) *model.AppError {
    69  	result := <-srv.Store.Job().UpdateStatus(job.Id, model.JOB_STATUS_SUCCESS)
    70  	return result.Err
    71  }
    72  
    73  func (srv *JobServer) SetJobError(job *model.Job, jobError *model.AppError) *model.AppError {
    74  	if jobError == nil {
    75  		result := <-srv.Store.Job().UpdateStatus(job.Id, model.JOB_STATUS_ERROR)
    76  		return result.Err
    77  	}
    78  
    79  	job.Status = model.JOB_STATUS_ERROR
    80  	job.Progress = -1
    81  	if job.Data == nil {
    82  		job.Data = make(map[string]string)
    83  	}
    84  	job.Data["error"] = jobError.Message + " (" + jobError.DetailedError + ")"
    85  
    86  	if result := <-srv.Store.Job().UpdateOptimistically(job, model.JOB_STATUS_IN_PROGRESS); result.Err != nil {
    87  		return result.Err
    88  	} else {
    89  		if !result.Data.(bool) {
    90  			if result := <-srv.Store.Job().UpdateOptimistically(job, model.JOB_STATUS_CANCEL_REQUESTED); result.Err != nil {
    91  				return result.Err
    92  			} else {
    93  				if !result.Data.(bool) {
    94  					return model.NewAppError("Jobs.SetJobError", "jobs.set_job_error.update.error", nil, "id="+job.Id, http.StatusInternalServerError)
    95  				}
    96  			}
    97  		}
    98  	}
    99  
   100  	return nil
   101  }
   102  
   103  func (srv *JobServer) SetJobCanceled(job *model.Job) *model.AppError {
   104  	result := <-srv.Store.Job().UpdateStatus(job.Id, model.JOB_STATUS_CANCELED)
   105  	return result.Err
   106  }
   107  
   108  func (srv *JobServer) RequestCancellation(jobId string) *model.AppError {
   109  	if result := <-srv.Store.Job().UpdateStatusOptimistically(jobId, model.JOB_STATUS_PENDING, model.JOB_STATUS_CANCELED); result.Err != nil {
   110  		return result.Err
   111  	} else if result.Data.(bool) {
   112  		return nil
   113  	}
   114  
   115  	if result := <-srv.Store.Job().UpdateStatusOptimistically(jobId, model.JOB_STATUS_IN_PROGRESS, model.JOB_STATUS_CANCEL_REQUESTED); result.Err != nil {
   116  		return result.Err
   117  	} else if result.Data.(bool) {
   118  		return nil
   119  	}
   120  
   121  	return model.NewAppError("Jobs.RequestCancellation", "jobs.request_cancellation.status.error", nil, "id="+jobId, http.StatusInternalServerError)
   122  }
   123  
   124  func (srv *JobServer) CancellationWatcher(ctx context.Context, jobId string, cancelChan chan interface{}) {
   125  	for {
   126  		select {
   127  		case <-ctx.Done():
   128  			l4g.Debug("CancellationWatcher for Job: %v Aborting as job has finished.", jobId)
   129  			return
   130  		case <-time.After(CANCEL_WATCHER_POLLING_INTERVAL * time.Millisecond):
   131  			l4g.Debug("CancellationWatcher for Job: %v polling.", jobId)
   132  			if result := <-srv.Store.Job().Get(jobId); result.Err == nil {
   133  				jobStatus := result.Data.(*model.Job)
   134  				if jobStatus.Status == model.JOB_STATUS_CANCEL_REQUESTED {
   135  					close(cancelChan)
   136  					return
   137  				}
   138  			}
   139  		}
   140  	}
   141  }
   142  
   143  func GenerateNextStartDateTime(now time.Time, nextStartTime time.Time) *time.Time {
   144  	nextTime := time.Date(now.Year(), now.Month(), now.Day(), nextStartTime.Hour(), nextStartTime.Minute(), 0, 0, time.Local)
   145  
   146  	if !now.Before(nextTime) {
   147  		nextTime = nextTime.AddDate(0, 0, 1)
   148  	}
   149  
   150  	return &nextTime
   151  }
   152  
   153  func (srv *JobServer) CheckForPendingJobsByType(jobType string) (bool, *model.AppError) {
   154  	if result := <-srv.Store.Job().GetCountByStatusAndType(model.JOB_STATUS_PENDING, jobType); result.Err != nil {
   155  		return false, result.Err
   156  	} else {
   157  		return result.Data.(int64) > 0, nil
   158  	}
   159  }
   160  
   161  func (srv *JobServer) GetLastSuccessfulJobByType(jobType string) (*model.Job, *model.AppError) {
   162  	if result := <-srv.Store.Job().GetNewestJobByStatusAndType(model.JOB_STATUS_SUCCESS, jobType); result.Err != nil {
   163  		return nil, result.Err
   164  	} else {
   165  		return result.Data.(*model.Job), nil
   166  	}
   167  }