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.9KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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. jobs := make([]*actions_model.ActionRunJob, 0, len(tasks))
  39. for _, task := range tasks {
  40. if err := db.WithTx(ctx, func(ctx context.Context) error {
  41. if err := actions_model.StopTask(ctx, task.ID, actions_model.StatusFailure); err != nil {
  42. return err
  43. }
  44. if err := task.LoadJob(ctx); err != nil {
  45. return err
  46. }
  47. jobs = append(jobs, task.Job)
  48. return nil
  49. }); err != nil {
  50. log.Warn("Cannot stop task %v: %v", task.ID, err)
  51. // go on
  52. } else if remove, err := actions.TransferLogs(ctx, task.LogFilename); err != nil {
  53. log.Warn("Cannot transfer logs of task %v: %v", task.ID, err)
  54. } else {
  55. remove()
  56. }
  57. }
  58. CreateCommitStatus(ctx, jobs...)
  59. return nil
  60. }
  61. // CancelAbandonedJobs cancels the jobs which have waiting status, but haven't been picked by a runner for a long time
  62. func CancelAbandonedJobs(ctx context.Context) error {
  63. jobs, _, err := actions_model.FindRunJobs(ctx, actions_model.FindRunJobOptions{
  64. Statuses: []actions_model.Status{actions_model.StatusWaiting, actions_model.StatusBlocked},
  65. UpdatedBefore: timeutil.TimeStamp(time.Now().Add(-abandonedJobTimeout).Unix()),
  66. })
  67. if err != nil {
  68. log.Warn("find abandoned tasks: %v", err)
  69. return err
  70. }
  71. now := timeutil.TimeStampNow()
  72. for _, job := range jobs {
  73. job.Status = actions_model.StatusCancelled
  74. job.Stopped = now
  75. if err := db.WithTx(ctx, func(ctx context.Context) error {
  76. _, err := actions_model.UpdateRunJob(ctx, job, nil, "status", "stopped")
  77. return err
  78. }); err != nil {
  79. log.Warn("cancel abandoned job %v: %v", job.ID, err)
  80. // go on
  81. }
  82. CreateCommitStatus(ctx, job)
  83. }
  84. return nil
  85. }