mirror of
https://github.com/go-gitea/gitea.git
synced 2026-11-02 13:44:16 +09:00
perf(actions): batch per-row queries in run, job and cancellation paths (#39723)
Several Actions code paths issued one or more queries per listed row. They now load in batch, with unchanged output. - API job list: tasks, steps and runners load in batch - API run list: latest attempts and their trigger users load in batch - Repository runs page: the jobs of all active runs load in one query - Cancelling previous runs and replacing concurrency group entries fetch their jobs in one query Per call with 50 rows on SQLite, base vs head: | Path | Queries | Time | | --- | --- | --- | | API job list | 254 → 6 | 12.9 → 1.9 ms | | API run list | 305 → 207 | 11.7 → 6.2 ms | | Runs page job loading | 100 → 1 | 6.5 → 0.47 ms | | `CancelPreviousJobs` | 546 → 496 | ~120 ms, per-job writes dominate | The remaining run list queries come from per-run repository conversion, which this PR doesn't change. --------- Co-authored-by: Zettat123 <zettat123@gmail.com> Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
10 files changed
+241
-121
No files matched your search
+63
-27
@@ -491,11 +491,7 @@ func ToActionWorkflowJob(ctx context.Context, repo *repo_model.Repository, task
|
||||
return nil, err
|
||||
}
|
||||
|
||||
status, conclusion := ToRunActionsStatus(job.Run, job.Status)
|
||||
var runnerID int64
|
||||
var runnerName string
|
||||
var steps []*api.ActionWorkflowStep
|
||||
|
||||
var runner *actions_model.ActionRunner
|
||||
if effectiveTaskID := job.EffectiveTaskID(); effectiveTaskID != 0 {
|
||||
if task == nil {
|
||||
task, _, err = db.GetByID[actions_model.ActionTask](ctx, effectiveTaskID)
|
||||
@@ -505,28 +501,68 @@ func ToActionWorkflowJob(ctx context.Context, repo *repo_model.Repository, task
|
||||
}
|
||||
|
||||
if task != nil {
|
||||
if task.Steps == nil {
|
||||
task.Steps, err = actions_model.GetTaskStepsByTaskID(ctx, task.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
task.Steps = util.SliceNilAsEmpty(task.Steps)
|
||||
}
|
||||
runnerID = task.RunnerID
|
||||
if runner, ok, _ := db.GetByID[actions_model.ActionRunner](ctx, runnerID); ok {
|
||||
runnerName = runner.Name
|
||||
}
|
||||
for i, step := range task.Steps {
|
||||
stepStatus, stepConclusion := ToActionsStatus(step.Status)
|
||||
steps = append(steps, &api.ActionWorkflowStep{
|
||||
Name: step.Name,
|
||||
Number: int64(i),
|
||||
Status: stepStatus,
|
||||
Conclusion: stepConclusion,
|
||||
StartedAt: step.Started.AsTime().UTC(),
|
||||
CompletedAt: step.Stopped.AsTime().UTC(),
|
||||
})
|
||||
if err := (actions_model.TaskList{task}).LoadSteps(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
runner, _, _ = db.GetByID[actions_model.ActionRunner](ctx, task.RunnerID)
|
||||
}
|
||||
}
|
||||
return toActionWorkflowJob(ctx, repo, task, runner, job), nil
|
||||
}
|
||||
|
||||
// ToActionWorkflowJobs requires job.Run.Repo to be loaded
|
||||
func ToActionWorkflowJobs(ctx context.Context, jobs []*actions_model.ActionRunJob) ([]*api.ActionWorkflowJob, error) {
|
||||
tasks, err := actions_model.GetTasksMapByIDs(ctx, container.FilterSlice(jobs, func(job *actions_model.ActionRunJob) (int64, bool) {
|
||||
taskID := job.EffectiveTaskID()
|
||||
return taskID, taskID != 0
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
taskList := actions_model.TaskList(slices.Collect(maps.Values(tasks)))
|
||||
if err := taskList.LoadSteps(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
runners, err := actions_model.GetRunnersMapByIDs(ctx, container.FilterSlice(taskList, func(task *actions_model.ActionTask) (int64, bool) {
|
||||
return task.RunnerID, task.RunnerID != 0
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*api.ActionWorkflowJob, len(jobs))
|
||||
for i, job := range jobs {
|
||||
task := tasks[job.EffectiveTaskID()]
|
||||
var runner *actions_model.ActionRunner
|
||||
if task != nil {
|
||||
runner = runners[task.RunnerID]
|
||||
}
|
||||
result[i] = toActionWorkflowJob(ctx, job.Run.Repo, task, runner, job)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func toActionWorkflowJob(ctx context.Context, repo *repo_model.Repository, task *actions_model.ActionTask, runner *actions_model.ActionRunner, job *actions_model.ActionRunJob) *api.ActionWorkflowJob {
|
||||
status, conclusion := ToRunActionsStatus(job.Run, job.Status)
|
||||
var runnerID int64
|
||||
var runnerName string
|
||||
var steps []*api.ActionWorkflowStep
|
||||
|
||||
if task != nil && job.EffectiveTaskID() != 0 {
|
||||
runnerID = task.RunnerID
|
||||
if runner != nil {
|
||||
runnerName = runner.Name
|
||||
}
|
||||
for i, step := range task.Steps {
|
||||
stepStatus, stepConclusion := ToActionsStatus(step.Status)
|
||||
steps = append(steps, &api.ActionWorkflowStep{
|
||||
Name: step.Name,
|
||||
Number: int64(i),
|
||||
Status: stepStatus,
|
||||
Conclusion: stepConclusion,
|
||||
StartedAt: step.Started.AsTime().UTC(),
|
||||
CompletedAt: step.Stopped.AsTime().UTC(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,7 +587,7 @@ func ToActionWorkflowJob(ctx context.Context, repo *repo_model.Repository, task
|
||||
CreatedAt: job.Created.AsTime().UTC(),
|
||||
StartedAt: job.Started.AsTime().UTC(),
|
||||
CompletedAt: job.Stopped.AsTime().UTC(),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func getActionWorkflowEntry(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, refName git.RefName, folder string, entry *git.TreeEntry) *api.ActionWorkflow {
|
||||
|
||||
Reference in new issue
Block a user