aboutsummaryrefslogtreecommitdiffstats
path: root/models/actions/run.go
diff options
context:
space:
mode:
authorBo-Yi Wu <appleboy.tw@gmail.com>2023-07-25 11:15:55 +0800
committerGitHub <noreply@github.com>2023-07-25 11:15:55 +0800
commit44781f9f5c4ede618660d8cfe42437f0e8dc22a0 (patch)
treeefcdc2e7876ede8c7e721432760e6ef9cefe4806 /models/actions/run.go
parent5db640abcd8608b065a1b390404bba2233220c95 (diff)
downloadgitea-44781f9f5c4ede618660d8cfe42437f0e8dc22a0.tar.gz
gitea-44781f9f5c4ede618660d8cfe42437f0e8dc22a0.zip
Implement auto-cancellation of concurrent jobs if the event is push (#25716)
- cancel running jobs if the event is push - Add a new function `CancelRunningJobs` to cancel all running jobs of a run - Update `FindRunOptions` struct to include `Ref` field and update its condition in `toConds` function - Implement auto cancellation of running jobs in the same workflow in `notify` function related task: https://github.com/go-gitea/gitea/pull/22751/ --------- Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> Signed-off-by: appleboy <appleboy.tw@gmail.com> Co-authored-by: Jason Song <i@wolfogre.com> Co-authored-by: delvh <dev.lh@web.de>
Diffstat (limited to 'models/actions/run.go')
-rw-r--r--models/actions/run.go69
1 files changed, 68 insertions, 1 deletions
diff --git a/models/actions/run.go b/models/actions/run.go
index 5396c612f6..ab6e319b1c 100644
--- a/models/actions/run.go
+++ b/models/actions/run.go
@@ -34,7 +34,7 @@ type ActionRun struct {
Index int64 `xorm:"index unique(repo_index)"` // a unique number for each run of a repository
TriggerUserID int64 `xorm:"index"`
TriggerUser *user_model.User `xorm:"-"`
- Ref string
+ Ref string `xorm:"index"` // the commit/tag/… that caused the run
CommitSHA string
IsForkPullRequest bool // If this is triggered by a PR from a forked repository or an untrusted user, we need to check if it is approved and limit permissions when running the workflow.
NeedApproval bool // may need approval if it's a fork pull request
@@ -164,6 +164,73 @@ func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) err
return err
}
+// CancelRunningJobs cancels all running and waiting jobs associated with a specific workflow.
+func CancelRunningJobs(ctx context.Context, repoID int64, ref, workflowID string) error {
+ // Find all runs in the specified repository, reference, and workflow with statuses 'Running' or 'Waiting'.
+ runs, total, err := FindRuns(ctx, FindRunOptions{
+ RepoID: repoID,
+ Ref: ref,
+ WorkflowID: workflowID,
+ Status: []Status{StatusRunning, StatusWaiting},
+ })
+ if err != nil {
+ return err
+ }
+
+ // If there are no runs found, there's no need to proceed with cancellation, so return nil.
+ if total == 0 {
+ return nil
+ }
+
+ // Iterate over each found run and cancel its associated jobs.
+ for _, run := range runs {
+ // Find all jobs associated with the current run.
+ jobs, _, err := FindRunJobs(ctx, FindRunJobOptions{
+ RunID: run.ID,
+ })
+ if err != nil {
+ return err
+ }
+
+ // Iterate over each job and attempt to cancel it.
+ for _, job := range jobs {
+ // Skip jobs that are already in a terminal state (completed, cancelled, etc.).
+ status := job.Status
+ if status.IsDone() {
+ continue
+ }
+
+ // If the job has no associated task (probably an error), set its status to 'Cancelled' and stop it.
+ if job.TaskID == 0 {
+ job.Status = StatusCancelled
+ job.Stopped = timeutil.TimeStampNow()
+
+ // Update the job's status and stopped time in the database.
+ n, err := UpdateRunJob(ctx, job, builder.Eq{"task_id": 0}, "status", "stopped")
+ if err != nil {
+ return err
+ }
+
+ // If the update affected 0 rows, it means the job has changed in the meantime, so we need to try again.
+ if n == 0 {
+ return fmt.Errorf("job has changed, try again")
+ }
+
+ // Continue with the next job.
+ continue
+ }
+
+ // If the job has an associated task, try to stop the task, effectively cancelling the job.
+ if err := StopTask(ctx, job.TaskID, StatusCancelled); err != nil {
+ return err
+ }
+ }
+ }
+
+ // Return nil to indicate successful cancellation of all running and waiting jobs.
+ return nil
+}
+
// InsertRun inserts a run
func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWorkflow) error {
ctx, commiter, err := db.TxContext(ctx)