From 70febee4873f41ea971d5a88e9dba2811dbcd80b Mon Sep 17 00:00:00 2001 From: Daniel Lindenfelser Date: Sat, 25 Jul 2026 17:35:26 +0200 Subject: [PATCH] Reap orphaned Gitea Actions job containers When the runner is stopped mid-job (reboot, autoUpgrade, gitea restart), its job container keeps running its `sleep 10800` entrypoint and is never cleaned up, and unused images pile up. Add a 15-min timer that removes a GITEA-ACTIONS-TASK-N container only when Gitea's DB reports that task as finished (status 1/2/3/4); running/unknown tasks are left untouched. Also prune unused actions networks/volumes and dangling images. Co-Authored-By: Claude Opus 4.8 --- modules/fileserver.nix | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/modules/fileserver.nix b/modules/fileserver.nix index f731f16..7f01330 100644 --- a/modules/fileserver.nix +++ b/modules/fileserver.nix @@ -240,6 +240,61 @@ }; }; + # Reaper für verwaiste Job-Container. Wird der Runner mitten in einem Job + # gestoppt (Reboot, autoUpgrade, Gitea-Neustart), läuft dessen Container mit + # "sleep 10800" bis zu 3h weiter und wird nie abgeräumt. Dieser Timer entfernt + # solche Container — aber NUR, wenn Gitea den zugehörigen Task als beendet + # führt (Status 1/2/3/4). Laufende (6) oder unbekannte Tasks bleiben unberührt. + systemd.services.gitea-runner-reaper = { + description = "Reap orphaned Gitea Actions job containers"; + after = [ "podman.service" ]; + serviceConfig = { + Type = "oneshot"; + User = "root"; + ExecStart = pkgs.writeShellScript "gitea-runner-reaper" '' + set -uo pipefail + PODMAN=${pkgs.podman}/bin/podman + + # Ohne laufenden Gitea-Container keine DB-Abfrage möglich -> nichts tun. + if ! $PODMAN container exists gitea; then + echo "gitea container not running — skipping reap" + exit 0 + fi + + $PODMAN ps --filter name=GITEA-ACTIONS-TASK- --format '{{.Names}}' | while read -r c; do + [ -n "$c" ] || continue + tid=$(printf '%s' "$c" | sed -n 's/^GITEA-ACTIONS-TASK-\([0-9]\+\)_.*/\1/p') + [ -n "$tid" ] || continue + # immutable=1: lock-freier read-only Zugriff auf die (von Gitea offene) DB. + st=$($PODMAN exec gitea sqlite3 "file:/data/gitea/gitea.db?immutable=1" \ + "SELECT status FROM action_task WHERE id=$tid;" 2>/dev/null) + # Status: 1=success 2=failure 3=cancelled 4=skipped 5=waiting 6=running + case "$st" in + 1|2|3|4) + echo "reaping orphan $c (task $tid finished, status=$st)" + $PODMAN rm -f "$c" >/dev/null 2>&1 || true + ;; + *) : ;; # 6/5/leer/unbekannt -> in Ruhe lassen + esac + done + + # Übrig gebliebene Actions-Netzwerke/Volumes und dangling Images aufräumen + # (prune entfernt nur, was an KEINEN laufenden Container gebunden ist). + $PODMAN network prune -f >/dev/null 2>&1 || true + $PODMAN volume prune -f >/dev/null 2>&1 || true + $PODMAN image prune -f >/dev/null 2>&1 || true + ''; + }; + }; + + systemd.timers.gitea-runner-reaper = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "*:0/15"; + Persistent = true; + }; + }; + ######################################## # Backup Services ########################################