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 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2019 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package cron
  6. import (
  7. "context"
  8. "time"
  9. "code.gitea.io/gitea/models"
  10. "code.gitea.io/gitea/modules/graceful"
  11. "code.gitea.io/gitea/modules/log"
  12. "code.gitea.io/gitea/modules/migrations"
  13. repo_module "code.gitea.io/gitea/modules/repository"
  14. "code.gitea.io/gitea/modules/setting"
  15. "code.gitea.io/gitea/modules/sync"
  16. mirror_service "code.gitea.io/gitea/services/mirror"
  17. "github.com/gogs/cron"
  18. )
  19. const (
  20. mirrorUpdate = "mirror_update"
  21. gitFsck = "git_fsck"
  22. checkRepos = "check_repos"
  23. archiveCleanup = "archive_cleanup"
  24. syncExternalUsers = "sync_external_users"
  25. deletedBranchesCleanup = "deleted_branches_cleanup"
  26. updateMigrationPosterID = "update_migration_post_id"
  27. )
  28. var c = cron.New()
  29. // Prevent duplicate running tasks.
  30. var taskStatusTable = sync.NewStatusTable()
  31. // Func defines a cron function body
  32. type Func func()
  33. // WithUnique wrap a cron func with an unique running check
  34. func WithUnique(name string, body func(context.Context)) Func {
  35. return func() {
  36. if !taskStatusTable.StartIfNotRunning(name) {
  37. return
  38. }
  39. defer taskStatusTable.Stop(name)
  40. graceful.GetManager().RunWithShutdownContext(body)
  41. }
  42. }
  43. // NewContext begins cron tasks
  44. // Each cron task is run within the shutdown context as a running server
  45. // AtShutdown the cron server is stopped
  46. func NewContext() {
  47. var (
  48. entry *cron.Entry
  49. err error
  50. )
  51. if setting.Cron.UpdateMirror.Enabled {
  52. entry, err = c.AddFunc("Update mirrors", setting.Cron.UpdateMirror.Schedule, WithUnique(mirrorUpdate, mirror_service.Update))
  53. if err != nil {
  54. log.Fatal("Cron[Update mirrors]: %v", err)
  55. }
  56. if setting.Cron.UpdateMirror.RunAtStart {
  57. entry.Prev = time.Now()
  58. entry.ExecTimes++
  59. go WithUnique(mirrorUpdate, mirror_service.Update)()
  60. }
  61. }
  62. if setting.Cron.RepoHealthCheck.Enabled {
  63. entry, err = c.AddFunc("Repository health check", setting.Cron.RepoHealthCheck.Schedule, WithUnique(gitFsck, func(ctx context.Context) {
  64. if err := repo_module.GitFsck(ctx); err != nil {
  65. log.Error("GitFsck: %s", err)
  66. }
  67. }))
  68. if err != nil {
  69. log.Fatal("Cron[Repository health check]: %v", err)
  70. }
  71. if setting.Cron.RepoHealthCheck.RunAtStart {
  72. entry.Prev = time.Now()
  73. entry.ExecTimes++
  74. go WithUnique(gitFsck, func(ctx context.Context) {
  75. if err := repo_module.GitFsck(ctx); err != nil {
  76. log.Error("GitFsck: %s", err)
  77. }
  78. })()
  79. }
  80. }
  81. if setting.Cron.CheckRepoStats.Enabled {
  82. entry, err = c.AddFunc("Check repository statistics", setting.Cron.CheckRepoStats.Schedule, WithUnique(checkRepos, models.CheckRepoStats))
  83. if err != nil {
  84. log.Fatal("Cron[Check repository statistics]: %v", err)
  85. }
  86. if setting.Cron.CheckRepoStats.RunAtStart {
  87. entry.Prev = time.Now()
  88. entry.ExecTimes++
  89. go WithUnique(checkRepos, models.CheckRepoStats)()
  90. }
  91. }
  92. if setting.Cron.ArchiveCleanup.Enabled {
  93. entry, err = c.AddFunc("Clean up old repository archives", setting.Cron.ArchiveCleanup.Schedule, WithUnique(archiveCleanup, models.DeleteOldRepositoryArchives))
  94. if err != nil {
  95. log.Fatal("Cron[Clean up old repository archives]: %v", err)
  96. }
  97. if setting.Cron.ArchiveCleanup.RunAtStart {
  98. entry.Prev = time.Now()
  99. entry.ExecTimes++
  100. go WithUnique(archiveCleanup, models.DeleteOldRepositoryArchives)()
  101. }
  102. }
  103. if setting.Cron.SyncExternalUsers.Enabled {
  104. entry, err = c.AddFunc("Synchronize external users", setting.Cron.SyncExternalUsers.Schedule, WithUnique(syncExternalUsers, models.SyncExternalUsers))
  105. if err != nil {
  106. log.Fatal("Cron[Synchronize external users]: %v", err)
  107. }
  108. if setting.Cron.SyncExternalUsers.RunAtStart {
  109. entry.Prev = time.Now()
  110. entry.ExecTimes++
  111. go WithUnique(syncExternalUsers, models.SyncExternalUsers)()
  112. }
  113. }
  114. if setting.Cron.DeletedBranchesCleanup.Enabled {
  115. entry, err = c.AddFunc("Remove old deleted branches", setting.Cron.DeletedBranchesCleanup.Schedule, WithUnique(deletedBranchesCleanup, models.RemoveOldDeletedBranches))
  116. if err != nil {
  117. log.Fatal("Cron[Remove old deleted branches]: %v", err)
  118. }
  119. if setting.Cron.DeletedBranchesCleanup.RunAtStart {
  120. entry.Prev = time.Now()
  121. entry.ExecTimes++
  122. go WithUnique(deletedBranchesCleanup, models.RemoveOldDeletedBranches)()
  123. }
  124. }
  125. entry, err = c.AddFunc("Update migrated repositories' issues and comments' posterid", setting.Cron.UpdateMigrationPosterID.Schedule, WithUnique(updateMigrationPosterID, migrations.UpdateMigrationPosterID))
  126. if err != nil {
  127. log.Fatal("Cron[Update migrated repositories]: %v", err)
  128. }
  129. entry.Prev = time.Now()
  130. entry.ExecTimes++
  131. go WithUnique(updateMigrationPosterID, migrations.UpdateMigrationPosterID)()
  132. c.Start()
  133. graceful.GetManager().RunAtShutdown(context.Background(), c.Stop)
  134. }
  135. // ListTasks returns all running cron tasks.
  136. func ListTasks() []*cron.Entry {
  137. return c.Entries()
  138. }