Repository navigation
fix(retention): purge tool-trace job artifacts in bounded batches - #3948
Merged
Merged
Conversation
Job artifact retention only deleted files stamped with retention_scope=indexing_artifacts, so tool-trace and transcript artifacts written by JobArtifacts were never purged and datamachine-artifacts/jobs grew without bound. - The default job-artifact policy now covers every artifact: unscoped (legacy) files and unregistered scopes age out on the default window, registered non-default scopes on their own window. - JobArtifacts stamps the default retention scope on tool-trace and transcript payloads. - Scheduled cleanup walks job dirs in bounded, resumable batches (job-ID cursor option, batch-size and runtime filters) using a streaming readdir + bounded heap instead of glob(); emptied dirs and stale temp files are removed. Closes #3937
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Job artifact retention never deleted
tool-trace.json(or transcript) artifacts, souploads/.../datamachine-artifacts/jobs/grew without bound (~510k orphaned job dirs / ~4 GB on events.extrachill.com). This PR makes the default job-artifact policy cover every artifact JobArtifacts writes, legacy files already on disk included. It also makes scheduled cleanup bounded and resumable, so the backlog drains in batches.Root cause
RetentionCleanup::cleanupJobArtifacts()→FileCleanup::cleanup_old_job_artifacts( 'indexing_artifacts', $days ).walk_old_job_artifacts()only deleted a*.jsonfile when its JSON containedretention_scope: indexing_artifacts.JobArtifactswrites tool traces (artifact_type: tool_trace) and transcripts with noretention_scope, so they never matched and were never deleted, even thoughretention showreported a 30-day window. The walk also calledglob()over every job dir in one request, which can't finish at 500k dirs.Approach
FileCleanup::job_artifact_matcher()):datamachine_job_artifacts_max_age_days, 30d)datamachine_job_artifact_retention_policies) expire on that scope's ownmax_age_dayscount/cleanup_old_job_artifacts( 'x', … )) keep the old stamped-only behaviour.JobArtifactsaddsretention_scope(default scope) to tool-trace and transcript payloads, so new files describe their own retention. The engine_data manifest is unchanged, so scoped-artifact summaries are unaffected.FileCleanup::cleanup_job_artifacts_batch( $scope, $days, $max_dirs, $cursor, $deadline ):$max_dirsnumeric job-dir IDs above$cursorin one streamingreaddir()pass with a boundedSplMaxHeap(memory scales with the batch, not the 500k total), then processes them in ascending order until the wall-clock deadlinenext_cursorand wraps it to 0 when a sweep completesRetentionCleanup::cleanupJobArtifacts()stores the cursor in the per-site optiondatamachine_job_artifacts_cleanup_cursordatamachine_job_artifacts_cleanup_batch_size(default 100000 dirs/run) anddatamachine_job_artifacts_cleanup_max_runtime_seconds(default 60). Daily runs drain the backlog over a handful of runs and stay well ahead of growth (~8k dirs/day), and the task can be run manually to drain faster..tmp-artifact-*files age out with the job. Non-artifact files keep their dir.Tests
New
tests/job-artifact-retention-smoke.php(34 assertions):RetentionCleanup::cleanupJobArtifacts()honours the batch filter and persists/resumes/resets the cursortests/job-artifact-hashable-smoke.phpnow also asserts that the tool-trace payload declares the default retention scope.How I ran them:
Homeboy smoke suite: 376/377 passed. The one failure is
tests/email-multi-inbox-forward-smoke.php("needs WordPress core for the real PHPMailer library"), which fails the same way on a cleanorigin/mainand isn't related to this change. The PHPUnit phase didn't run because of an environment mismatch:wp_codebox_database_service requires database_type=mysql, from the test settings vs.database_type: sqlitein homeboy.json. With--pathat the monorepo root, the review discovers no tests on this branch or on a cleanorigin/main.Closes #3937
AI disclosure: implemented by an AI agent (Extra Chill Bot) at Chris's direction.
Finalized outside Homeboy Cook (direct fallback authorized by Chris; Cook blocked by homeboy#18081 lab monorepo gate + local provider auth failure).