summaryrefslogtreecommitdiffstats
path: root/services/actions/cleanup.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel@debian.org>2024-10-18 20:33:49 +0200
committerDaniel Baumann <daniel@debian.org>2024-12-12 23:57:56 +0100
commite68b9d00a6e05b3a941f63ffb696f91e554ac5ec (patch)
tree97775d6c13b0f416af55314eb6a89ef792474615 /services/actions/cleanup.go
parentInitial commit. (diff)
downloadforgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.tar.xz
forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.zip
Adding upstream version 9.0.3.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'services/actions/cleanup.go')
-rw-r--r--services/actions/cleanup.go128
1 files changed, 128 insertions, 0 deletions
diff --git a/services/actions/cleanup.go b/services/actions/cleanup.go
new file mode 100644
index 0000000..34fa268
--- /dev/null
+++ b/services/actions/cleanup.go
@@ -0,0 +1,128 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package actions
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "os"
+ "time"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ actions_module "code.gitea.io/gitea/modules/actions"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/storage"
+ "code.gitea.io/gitea/modules/timeutil"
+)
+
+// Cleanup removes expired actions logs, data and artifacts
+func Cleanup(ctx context.Context) error {
+ // clean up expired artifacts
+ if err := CleanupArtifacts(ctx); err != nil {
+ return fmt.Errorf("cleanup artifacts: %w", err)
+ }
+
+ // clean up old logs
+ if err := CleanupLogs(ctx); err != nil {
+ return fmt.Errorf("cleanup logs: %w", err)
+ }
+
+ return nil
+}
+
+// CleanupArtifacts removes expired add need-deleted artifacts and set records expired status
+func CleanupArtifacts(taskCtx context.Context) error {
+ if err := cleanExpiredArtifacts(taskCtx); err != nil {
+ return err
+ }
+ return cleanNeedDeleteArtifacts(taskCtx)
+}
+
+func cleanExpiredArtifacts(taskCtx context.Context) error {
+ artifacts, err := actions_model.ListNeedExpiredArtifacts(taskCtx)
+ if err != nil {
+ return err
+ }
+ log.Info("Found %d expired artifacts", len(artifacts))
+ for _, artifact := range artifacts {
+ if err := actions_model.SetArtifactExpired(taskCtx, artifact.ID); err != nil {
+ log.Error("Cannot set artifact %d expired: %v", artifact.ID, err)
+ continue
+ }
+ if err := storage.ActionsArtifacts.Delete(artifact.StoragePath); err != nil {
+ log.Error("Cannot delete artifact %d: %v", artifact.ID, err)
+ continue
+ }
+ log.Info("Artifact %d set expired", artifact.ID)
+ }
+ return nil
+}
+
+// deleteArtifactBatchSize is the batch size of deleting artifacts
+const deleteArtifactBatchSize = 100
+
+func cleanNeedDeleteArtifacts(taskCtx context.Context) error {
+ for {
+ artifacts, err := actions_model.ListPendingDeleteArtifacts(taskCtx, deleteArtifactBatchSize)
+ if err != nil {
+ return err
+ }
+ log.Info("Found %d artifacts pending deletion", len(artifacts))
+ for _, artifact := range artifacts {
+ if err := actions_model.SetArtifactDeleted(taskCtx, artifact.ID); err != nil {
+ log.Error("Cannot set artifact %d deleted: %v", artifact.ID, err)
+ continue
+ }
+ if err := storage.ActionsArtifacts.Delete(artifact.StoragePath); err != nil {
+ log.Error("Cannot delete artifact %d: %v", artifact.ID, err)
+ continue
+ }
+ log.Info("Artifact %d set deleted", artifact.ID)
+ }
+ if len(artifacts) < deleteArtifactBatchSize {
+ log.Debug("No more artifacts pending deletion")
+ break
+ }
+ }
+ return nil
+}
+
+const deleteLogBatchSize = 100
+
+// CleanupLogs removes logs which are older than the configured retention time
+func CleanupLogs(ctx context.Context) error {
+ olderThan := timeutil.TimeStampNow().AddDuration(-time.Duration(setting.Actions.LogRetentionDays) * 24 * time.Hour)
+
+ count := 0
+ for {
+ tasks, err := actions_model.FindOldTasksToExpire(ctx, olderThan, deleteLogBatchSize)
+ if err != nil {
+ return fmt.Errorf("find old tasks: %w", err)
+ }
+ for _, task := range tasks {
+ if err := actions_module.RemoveLogs(ctx, task.LogInStorage, task.LogFilename); err != nil && !errors.Is(err, os.ErrNotExist) {
+ log.Error("Failed to remove log %s (in storage %v) of task %v: %v", task.LogFilename, task.LogInStorage, task.ID, err)
+ // do not return error here, continue to next task
+ continue
+ }
+ task.LogIndexes = nil // clear log indexes since it's a heavy field
+ task.LogExpired = true
+ if err := actions_model.UpdateTask(ctx, task, "log_indexes", "log_expired"); err != nil {
+ log.Error("Failed to update task %v: %v", task.ID, err)
+ // do not return error here, continue to next task
+ continue
+ }
+ count++
+ log.Trace("Removed log %s of task %v", task.LogFilename, task.ID)
+ }
+ if len(tasks) < deleteLogBatchSize {
+ break
+ }
+ }
+
+ log.Info("Removed %d logs", count)
+ return nil
+}