gitea
Зеркало из https://github.com/go-gitea/gitea
1// Copyright 2014 The Gogs Authors. All rights reserved.
2// Copyright 2019 The Gitea Authors. All rights reserved.
3// SPDX-License-Identifier: MIT
4
5package cron
6
7import (
8"context"
9"runtime/pprof"
10"time"
11
12"code.gitea.io/gitea/modules/graceful"
13"code.gitea.io/gitea/modules/process"
14"code.gitea.io/gitea/modules/sync"
15"code.gitea.io/gitea/modules/translation"
16
17"github.com/go-co-op/gocron"
18)
19
20var scheduler = gocron.NewScheduler(time.Local)
21
22// Prevent duplicate running tasks.
23var taskStatusTable = sync.NewStatusTable()
24
25// NewContext begins cron tasks
26// Each cron task is run within the shutdown context as a running server
27// AtShutdown the cron server is stopped
28func NewContext(original context.Context) {
29defer pprof.SetGoroutineLabels(original)
30_, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().ShutdownContext(), "Service: Cron", process.SystemProcessType, true)
31initBasicTasks()
32initExtendedTasks()
33initActionsTasks()
34
35lock.Lock()
36for _, task := range tasks {
37if task.IsEnabled() && task.DoRunAtStart() {
38go task.Run()
39}
40}
41
42scheduler.StartAsync()
43started = true
44lock.Unlock()
45graceful.GetManager().RunAtShutdown(context.Background(), func() {
46scheduler.Stop()
47lock.Lock()
48started = false
49lock.Unlock()
50finished()
51})
52}
53
54// TaskTableRow represents a task row in the tasks table
55type TaskTableRow struct {
56Name string
57Spec string
58Next time.Time
59Prev time.Time
60Status string
61LastMessage string
62LastDoer string
63ExecTimes int64
64task *Task
65}
66
67func (t *TaskTableRow) FormatLastMessage(locale translation.Locale) string {
68if t.Status == "finished" {
69return t.task.GetConfig().FormatMessage(locale, t.Name, t.Status, t.LastDoer)
70}
71
72return t.task.GetConfig().FormatMessage(locale, t.Name, t.Status, t.LastDoer, t.LastMessage)
73}
74
75// TaskTable represents a table of tasks
76type TaskTable []*TaskTableRow
77
78// ListTasks returns all running cron tasks.
79func ListTasks() TaskTable {
80jobs := scheduler.Jobs()
81jobMap := map[string]*gocron.Job{}
82for _, job := range jobs {
83// the first tag is the task name
84tags := job.Tags()
85if len(tags) == 0 { // should never happen
86continue
87}
88jobMap[job.Tags()[0]] = job
89}
90
91lock.Lock()
92defer lock.Unlock()
93
94tTable := make([]*TaskTableRow, 0, len(tasks))
95for _, task := range tasks {
96spec := "-"
97var (
98next time.Time
99prev time.Time
100)
101if e, ok := jobMap[task.Name]; ok {
102tags := e.Tags()
103if len(tags) > 1 {
104spec = tags[1] // the second tag is the task spec
105}
106next = e.NextRun()
107prev = e.PreviousRun()
108}
109
110task.lock.Lock()
111// If the manual run is after the cron run, use that instead.
112if prev.Before(task.LastRun) {
113prev = task.LastRun
114}
115tTable = append(tTable, &TaskTableRow{
116Name: task.Name,
117Spec: spec,
118Next: next,
119Prev: prev,
120ExecTimes: task.ExecTimes,
121LastMessage: task.LastMessage,
122Status: task.Status,
123LastDoer: task.LastDoer,
124task: task,
125})
126task.lock.Unlock()
127}
128
129return tTable
130}
131