You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cron.go 3.0KB

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