diff options
author | Daniel Baumann <daniel@debian.org> | 2024-10-18 20:33:49 +0200 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-12-12 23:57:56 +0100 |
commit | e68b9d00a6e05b3a941f63ffb696f91e554ac5ec (patch) | |
tree | 97775d6c13b0f416af55314eb6a89ef792474615 /services/cron/cron.go | |
parent | Initial commit. (diff) | |
download | forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.tar.xz forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.zip |
Adding upstream version 9.0.3.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to '')
-rw-r--r-- | services/cron/cron.go | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/services/cron/cron.go b/services/cron/cron.go new file mode 100644 index 0000000..3c5737e --- /dev/null +++ b/services/cron/cron.go @@ -0,0 +1,130 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Copyright 2019 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package cron + +import ( + "context" + "runtime/pprof" + "time" + + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/sync" + "code.gitea.io/gitea/modules/translation" + + "github.com/go-co-op/gocron" +) + +var scheduler = gocron.NewScheduler(time.Local) + +// Prevent duplicate running tasks. +var taskStatusTable = sync.NewStatusTable() + +// NewContext begins cron tasks +// Each cron task is run within the shutdown context as a running server +// AtShutdown the cron server is stopped +func NewContext(original context.Context) { + defer pprof.SetGoroutineLabels(original) + _, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().ShutdownContext(), "Service: Cron", process.SystemProcessType, true) + initBasicTasks() + initExtendedTasks() + initActionsTasks() + + lock.Lock() + for _, task := range tasks { + if task.IsEnabled() && task.DoRunAtStart() { + go task.Run() + } + } + + scheduler.StartAsync() + started = true + lock.Unlock() + graceful.GetManager().RunAtShutdown(context.Background(), func() { + scheduler.Stop() + lock.Lock() + started = false + lock.Unlock() + finished() + }) +} + +// TaskTableRow represents a task row in the tasks table +type TaskTableRow struct { + Name string + Spec string + Next time.Time + Prev time.Time + Status string + LastMessage string + LastDoer string + ExecTimes int64 + task *Task +} + +func (t *TaskTableRow) FormatLastMessage(locale translation.Locale) string { + if t.Status == "finished" { + return t.task.GetConfig().FormatMessage(locale, t.Name, t.Status, t.LastDoer) + } + + return t.task.GetConfig().FormatMessage(locale, t.Name, t.Status, t.LastDoer, t.LastMessage) +} + +// TaskTable represents a table of tasks +type TaskTable []*TaskTableRow + +// ListTasks returns all running cron tasks. +func ListTasks() TaskTable { + jobs := scheduler.Jobs() + jobMap := map[string]*gocron.Job{} + for _, job := range jobs { + // the first tag is the task name + tags := job.Tags() + if len(tags) == 0 { // should never happen + continue + } + jobMap[job.Tags()[0]] = job + } + + lock.Lock() + defer lock.Unlock() + + tTable := make([]*TaskTableRow, 0, len(tasks)) + for _, task := range tasks { + spec := "-" + var ( + next time.Time + prev time.Time + ) + if e, ok := jobMap[task.Name]; ok { + tags := e.Tags() + if len(tags) > 1 { + spec = tags[1] // the second tag is the task spec + } + next = e.NextRun() + prev = e.PreviousRun() + } + + task.lock.Lock() + // If the manual run is after the cron run, use that instead. + if prev.Before(task.LastRun) { + prev = task.LastRun + } + tTable = append(tTable, &TaskTableRow{ + Name: task.Name, + Spec: spec, + Next: next, + Prev: prev, + ExecTimes: task.ExecTimes, + LastMessage: task.LastMessage, + Status: task.Status, + LastDoer: task.LastDoer, + task: task, + }) + task.lock.Unlock() + } + + return tTable +} |