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