PLT-6916: Redesign the jobs package and Jobserver. (#6733)

This commit redesigns the jobserver to be based around an architecture
of "workers", which carry out jobs of a particular type, and "jobs"
which are a unit of work carried by a particular worker. It also
introduces "schedulers" which are responsible for scheduling jobs of a
particular type automatically (jobs can also be scheduled manually when
apropriate).

Workers may be run many times, either in instances of the platform
binary, or the standalone jobserver binary. In any mattermost cluster,
only one instance of platform OR jobserver must run the schedulers. At
the moment this is controlled by a config variable, but in future will
be controlled through the cluster leader election process.
Этот коммит содержится в:
George Goldberg
2017-07-07 15:21:02 +01:00
коммит произвёл GitHub
родитель 6e0f5f0969
Коммит 0495a51949
31 изменённых файлов: 1370 добавлений и 583 удалений

Просмотреть файл

@@ -2790,22 +2790,22 @@ func (c *Client4) OpenGraph(url string) (map[string]string, *Response) {
// Jobs Section
// GetJobStatus gets the status of a single job.
func (c *Client4) GetJobStatus(id string) (*JobStatus, *Response) {
// GetJob gets a single job.
func (c *Client4) GetJob(id string) (*Job, *Response) {
if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/%v/status", id), ""); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return JobStatusFromJson(r.Body), BuildResponse(r)
return JobFromJson(r.Body), BuildResponse(r)
}
}
// GetJobStatusesByType gets the status of all jobs of a given type, sorted with the job that most recently started first.
func (c *Client4) GetJobStatusesByType(jobType string, page int, perPage int) ([]*JobStatus, *Response) {
// GetJobsByType gets all jobs of a given type, sorted with the job that most recently started first.
func (c *Client4) GetJobsByType(jobType string, page int, perPage int) ([]*Job, *Response) {
if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/type/%v/statuses?page=%v&per_page=%v", jobType, page, perPage), ""); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return JobStatusesFromJson(r.Body), BuildResponse(r)
return JobsFromJson(r.Body), BuildResponse(r)
}
}

Просмотреть файл

@@ -436,6 +436,11 @@ type DataRetentionSettings struct {
Enable *bool
}
type JobSettings struct {
RunJobs *bool
RunScheduler *bool
}
type Config struct {
ServiceSettings ServiceSettings
TeamSettings TeamSettings
@@ -462,6 +467,7 @@ type Config struct {
WebrtcSettings WebrtcSettings
ElasticSearchSettings ElasticSearchSettings
DataRetentionSettings DataRetentionSettings
JobSettings JobSettings
}
func (o *Config) ToJson() string {
@@ -1380,6 +1386,16 @@ func (o *Config) SetDefaults() {
*o.DataRetentionSettings.Enable = false
}
if o.JobSettings.RunJobs == nil {
o.JobSettings.RunJobs = new(bool)
*o.JobSettings.RunJobs = true
}
if o.JobSettings.RunScheduler == nil {
o.JobSettings.RunScheduler = new(bool)
*o.JobSettings.RunScheduler = true
}
o.defaultWebrtcSettings()
}

Просмотреть файл

@@ -3,7 +3,84 @@
package model
type Job interface {
import (
"encoding/json"
"io"
)
const (
JOB_TYPE_DATA_RETENTION = "data_retention"
JOB_TYPE_SEARCH_INDEXING = "search_indexing"
JOB_STATUS_PENDING = "pending"
JOB_STATUS_IN_PROGRESS = "in_progress"
JOB_STATUS_SUCCESS = "success"
JOB_STATUS_ERROR = "error"
JOB_STATUS_CANCEL_REQUESTED = "cancel_requested"
JOB_STATUS_CANCELED = "canceled"
)
type Job struct {
Id string `json:"id"`
Type string `json:"type"`
Priority int64 `json:"priority"`
CreateAt int64 `json:"create_at"`
StartAt int64 `json:"start_at"`
LastActivityAt int64 `json:"last_activity_at"`
Status string `json:"status"`
Progress int64 `json:"progress"`
Data map[string]interface{} `json:"data"`
}
func (js *Job) ToJson() string {
if b, err := json.Marshal(js); err != nil {
return ""
} else {
return string(b)
}
}
func JobFromJson(data io.Reader) *Job {
var status Job
if err := json.NewDecoder(data).Decode(&status); err == nil {
return &status
} else {
return nil
}
}
func JobsToJson(jobs []*Job) string {
if b, err := json.Marshal(jobs); err != nil {
return ""
} else {
return string(b)
}
}
func JobsFromJson(data io.Reader) []*Job {
var jobs []*Job
if err := json.NewDecoder(data).Decode(&jobs); err == nil {
return jobs
} else {
return nil
}
}
func (js *Job) DataToJson() string {
if b, err := json.Marshal(js.Data); err != nil {
return ""
} else {
return string(b)
}
}
type Worker interface {
Run()
Stop()
JobChannel() chan<- Job
}
type Scheduler interface {
Run()
Stop()
}

Просмотреть файл

@@ -1,59 +0,0 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"encoding/json"
"io"
)
const (
JOB_TYPE_DATA_RETENTION = "data_retention"
JOB_TYPE_SEARCH_INDEXING = "search_indexing"
)
type JobStatus struct {
Id string `json:"id"`
Type string `json:"type"`
StartAt int64 `json:"start_at"`
LastActivityAt int64 `json:"last_activity_at"`
LastRunStartedAt int64 `json:"last_run_started_at"`
LastRunCompletedAt int64 `json:"last_run_completed_at"`
Status string `json:"status"`
Data map[string]interface{} `json:"data"`
}
func (js *JobStatus) ToJson() string {
if b, err := json.Marshal(js); err != nil {
return ""
} else {
return string(b)
}
}
func JobStatusFromJson(data io.Reader) *JobStatus {
var status JobStatus
if err := json.NewDecoder(data).Decode(&status); err == nil {
return &status
} else {
return nil
}
}
func JobStatusesToJson(statuses []*JobStatus) string {
if b, err := json.Marshal(statuses); err != nil {
return ""
} else {
return string(b)
}
}
func JobStatusesFromJson(data io.Reader) []*JobStatus {
var statuses []*JobStatus
if err := json.NewDecoder(data).Decode(&statuses); err == nil {
return statuses
} else {
return nil
}
}