diff options
author | Bo-Yi Wu <appleboy.tw@gmail.com> | 2023-07-25 11:15:55 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-25 11:15:55 +0800 |
commit | 44781f9f5c4ede618660d8cfe42437f0e8dc22a0 (patch) | |
tree | efcdc2e7876ede8c7e721432760e6ef9cefe4806 /models/actions/run.go | |
parent | 5db640abcd8608b065a1b390404bba2233220c95 (diff) | |
download | gitea-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.go | 69 |
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) |