Skip to content

feat(server): prune stale per-job log files on startup (#131)#135

Merged
Sootopolis merged 1 commit into
mainfrom
wip
Jun 26, 2026
Merged

feat(server): prune stale per-job log files on startup (#131)#135
Sootopolis merged 1 commit into
mainfrom
wip

Conversation

@Sootopolis

Copy link
Copy Markdown
Owner

What

Adds a startup sweep that deletes per-job log files (${JOB_LOGS_DIR}/<jobId>.log) older than a DB-owned retention window, mirroring the existing api_response_cache retention pattern. The job-log directory previously grew without bound (one file per job run, never pruned).

  • New AppSetting.JobLogRetentionDays key — default 14 days, runtime-tunable via SQL, no schema churn (generic app_setting key/value store).
  • FileSink.sweepBefore(logDir, cutoff) — best-effort *.log sweep filtered by file mtime; non-fatal IO errors per file are swallowed so one bad file never aborts the sweep; non-log files untouched.
  • Wired into JobRunner.live startup beside markOrphansAsFailed (only site holding both logDir and pgClient). A whole-sweep failure logs a warning and lets the server boot — retention is never a startup blocker.

Fixes

Closes #131.

Testing

  • sbt test — full suite green (954 passed) via pre-push hook.
  • New DB-free unit test TestJobLogSink.testSweepBeforeDeletesOldLogsOnly: old .log swept, fresh .log + non-.log file kept, count == 1. mtime pinned both sides to avoid filesystem-granularity flake.
  • TestJobRunner (15) confirms the layer still constructs with the sweep wired.

🤖 Generated with Claude Code

https://claude.ai/code/session_01ETHm6wCYdzFuB3kNEBayjF

Per-job log files (${JOB_LOGS_DIR}/<jobId>.log) were never pruned, so the
directory grew without bound — one file per job run, forever. Mirror the
existing api_response_cache retention: a DB-owned, runtime-tunable window
swept once at startup, no rotation daemon, no schema churn.

JobRunner.live is the only startup site holding both logDir and pgClient,
so the sweep lives there beside markOrphansAsFailed. Retention defaults to
14 days (longer than the cache's 7 — logs are small and diagnostic-useful)
via a new job_log_retention_days AppSetting key. The sweep is best-effort:
a non-fatal IO error on one file is swallowed so it never aborts the sweep,
and a whole-sweep failure logs a warning and lets the server boot rather
than blocking startup. Filter by file mtime so any *.log name is handled
and "stale = not touched in N days" stays the semantic; non-log files in
the directory are left untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETHm6wCYdzFuB3kNEBayjF
@Sootopolis
Sootopolis merged commit 8f7fa71 into main Jun 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Per-job log files have no retention/cleanup — logs/jobs grows unbounded

1 participant