Skip to content

Commit 974c1f2

Browse files
committed
ensure CleanupEphemeralRunners does work correctly
1 parent 2d555c8 commit 974c1f2

File tree

2 files changed

+42
-7
lines changed

2 files changed

+42
-7
lines changed

services/actions/cleanup.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"code.gitea.io/gitea/modules/setting"
1616
"code.gitea.io/gitea/modules/storage"
1717
"code.gitea.io/gitea/modules/timeutil"
18+
"xorm.io/builder"
1819
)
1920

2021
// Cleanup removes expired actions logs, data, artifacts and used ephemeral runners
@@ -134,15 +135,17 @@ const deleteEphemeralRunnerBatchSize = 100
134135

135136
// CleanupEphemeralRunners removes used ephemeral runners which are no longer able to process jobs
136137
func CleanupEphemeralRunners(ctx context.Context) error {
137-
runners := []*actions_model.ActionRunner{}
138-
err := db.GetEngine(ctx).Join("INNER", "`action_task`", "`action_task`.`runner_id` = `action_runner`.`id`").Where("`action_runner`.`ephemeral` = ? and `action_task`.`status` NOT IN (?, ?, ?)", true, actions_model.StatusWaiting, actions_model.StatusRunning, actions_model.StatusBlocked).Limit(deleteEphemeralRunnerBatchSize).Find(&runners)
138+
subQuery := builder.Select("`action_runner`.id").
139+
From("`action_runner`").
140+
Join("INNER", "`action_task`", "`action_task`.`runner_id` = `action_runner`.`id`").
141+
Where(builder.Eq{"`action_runner`.`ephemeral`": true}).
142+
And(builder.NotIn("`action_task`.`status`", actions_model.StatusWaiting, actions_model.StatusRunning, actions_model.StatusBlocked))
143+
b := builder.Delete(builder.In("id", subQuery)).From("`action_runner`")
144+
res, err := db.GetEngine(ctx).Exec(b)
139145
if err != nil {
140146
return fmt.Errorf("find runners: %w", err)
141147
}
142-
count, err := db.GetEngine(ctx).Delete(&runners)
143-
if err != nil {
144-
return fmt.Errorf("delete runners: %w", err)
145-
}
146-
log.Info("Removed %d runners", count)
148+
affected, err := res.RowsAffected()
149+
log.Info("Removed %d runners", affected)
147150
return nil
148151
}

tests/integration/actions_job_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"code.gitea.io/gitea/modules/json"
2222
"code.gitea.io/gitea/modules/setting"
2323
api "code.gitea.io/gitea/modules/structs"
24+
actions_service "code.gitea.io/gitea/services/actions"
2425

2526
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
2627
"connectrpc.com/connect"
@@ -452,6 +453,9 @@ func TestActionsGiteaContextEphemeral(t *testing.T) {
452453
runner := newMockRunner()
453454
runner.registerAsRepoRunner(t, baseRepo.OwnerName, baseRepo.Name, "mock-runner", []string{"ubuntu-latest"}, true)
454455

456+
// verify CleanupEphemeralRunners does not remove this runner
457+
actions_service.CleanupEphemeralRunners(t.Context())
458+
455459
// init the workflow
456460
wfTreePath := ".gitea/workflows/pull.yml"
457461
wfFileContent := `name: Pull Request
@@ -524,11 +528,18 @@ jobs:
524528
token := gtCtx["token"].GetStringValue()
525529
assert.Equal(t, actionTask.TokenLastEight, token[len(token)-8:])
526530

531+
// verify CleanupEphemeralRunners does not remove this runner
532+
actions_service.CleanupEphemeralRunners(t.Context())
533+
527534
resp, err := runner.client.runnerServiceClient.FetchTask(t.Context(), connect.NewRequest(&runnerv1.FetchTaskRequest{
528535
TasksVersion: 0,
529536
}))
530537
assert.NoError(t, err)
531538
assert.Nil(t, resp.Msg.Task)
539+
540+
// verify CleanupEphemeralRunners does not remove this runner
541+
actions_service.CleanupEphemeralRunners(t.Context())
542+
532543
runner.client.runnerServiceClient.UpdateTask(t.Context(), connect.NewRequest(&runnerv1.UpdateTaskRequest{
533544
State: &runnerv1.TaskState{
534545
Id: actionTask.ID,
@@ -546,6 +557,27 @@ jobs:
546557
}))
547558
assert.Error(t, err)
548559
assert.Nil(t, resp)
560+
561+
// create an runner that picks a job and get force cancelled
562+
runnerToBeRemoved := newMockRunner()
563+
runnerToBeRemoved.registerAsRepoRunner(t, baseRepo.OwnerName, baseRepo.Name, "mock-runner-to-be-removed", []string{"ubuntu-latest"}, true)
564+
565+
taskToStopApiObj := runnerToBeRemoved.fetchTask(t)
566+
567+
taskToStop := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: taskToStopApiObj.Id})
568+
569+
// verify CleanupEphemeralRunners does not remove the custom crafted runner
570+
actions_service.CleanupEphemeralRunners(t.Context())
571+
572+
runnerToRemove := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: taskToStop.RunnerID})
573+
574+
err = actions_model.StopTask(t.Context(), taskToStop.ID, actions_model.StatusFailure)
575+
assert.NoError(t, err)
576+
577+
// verify CleanupEphemeralRunners does remove the custom crafted runner
578+
actions_service.CleanupEphemeralRunners(t.Context())
579+
580+
unittest.AssertNotExistsBean(t, runnerToRemove)
549581
})
550582
}
551583

0 commit comments

Comments
 (0)