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.

clear_tasks.go 2.8KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // Copyright 2022 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package actions
  4. import (
  5. "context"
  6. "fmt"
  7. "time"
  8. actions_model "code.gitea.io/gitea/models/actions"
  9. "code.gitea.io/gitea/models/db"
  10. "code.gitea.io/gitea/modules/actions"
  11. "code.gitea.io/gitea/modules/log"
  12. "code.gitea.io/gitea/modules/timeutil"
  13. )
  14. const (
  15. zombieTaskTimeout = 10 * time.Minute
  16. endlessTaskTimeout = 3 * time.Hour
  17. abandonedJobTimeout = 24 * time.Hour
  18. )
  19. // StopZombieTasks stops the task which have running status, but haven't been updated for a long time
  20. func StopZombieTasks(ctx context.Context) error {
  21. return stopTasks(ctx, actions_model.FindTaskOptions{
  22. Status: actions_model.StatusRunning,
  23. UpdatedBefore: timeutil.TimeStamp(time.Now().Add(-zombieTaskTimeout).Unix()),
  24. })
  25. }
  26. // StopEndlessTasks stops the tasks which have running status and continuous updates, but don't end for a long time
  27. func StopEndlessTasks(ctx context.Context) error {
  28. return stopTasks(ctx, actions_model.FindTaskOptions{
  29. Status: actions_model.StatusRunning,
  30. StartedBefore: timeutil.TimeStamp(time.Now().Add(-endlessTaskTimeout).Unix()),
  31. })
  32. }
  33. func stopTasks(ctx context.Context, opts actions_model.FindTaskOptions) error {
  34. tasks, err := actions_model.FindTasks(ctx, opts)
  35. if err != nil {
  36. return fmt.Errorf("find tasks: %w", err)
  37. }
  38. for _, task := range tasks {
  39. if err := db.WithTx(ctx, func(ctx context.Context) error {
  40. if err := actions_model.StopTask(ctx, task.ID, actions_model.StatusFailure); err != nil {
  41. return err
  42. }
  43. if err := task.LoadJob(ctx); err != nil {
  44. return err
  45. }
  46. return CreateCommitStatus(ctx, task.Job)
  47. }); err != nil {
  48. log.Warn("Cannot stop task %v: %v", task.ID, err)
  49. // go on
  50. } else if remove, err := actions.TransferLogs(ctx, task.LogFilename); err != nil {
  51. log.Warn("Cannot transfer logs of task %v: %v", task.ID, err)
  52. } else {
  53. remove()
  54. }
  55. }
  56. return nil
  57. }
  58. // CancelAbandonedJobs cancels the jobs which have waiting status, but haven't been picked by a runner for a long time
  59. func CancelAbandonedJobs(ctx context.Context) error {
  60. jobs, _, err := actions_model.FindRunJobs(ctx, actions_model.FindRunJobOptions{
  61. Statuses: []actions_model.Status{actions_model.StatusWaiting, actions_model.StatusBlocked},
  62. UpdatedBefore: timeutil.TimeStamp(time.Now().Add(-abandonedJobTimeout).Unix()),
  63. })
  64. if err != nil {
  65. log.Warn("find abandoned tasks: %v", err)
  66. return err
  67. }
  68. now := timeutil.TimeStampNow()
  69. for _, job := range jobs {
  70. job.Status = actions_model.StatusCancelled
  71. job.Stopped = now
  72. if err := db.WithTx(ctx, func(ctx context.Context) error {
  73. if _, err := actions_model.UpdateRunJob(ctx, job, nil, "status", "stopped"); err != nil {
  74. return err
  75. }
  76. return CreateCommitStatus(ctx, job)
  77. }); err != nil {
  78. log.Warn("cancel abandoned job %v: %v", job.ID, err)
  79. // go on
  80. }
  81. }
  82. return nil
  83. }