Skip to content

JobLog retention check via data integrity framework (#1188) #1277

Description

@mihow

Background

PR #1259 moves job-log persistence onto an append-only JobLog child table. Drops the old per-job max_log_length = 1000 ceiling that the JSONB write path enforced. New table grows unbounded — needs explicit retention, otherwise high-traffic deployments will accumulate pathologically large jobs_joblog.

Approach

Implement retention as a module under the data integrity check framework being introduced in #1188 — ami/main/checks/joblogs.py:

  • get_joblog_retention_violations(project_id=None, max_age_days=N) — returns rows past the cutoff
  • reconcile_joblog_retention(..., dry_run=True) — deletes excess rows, returns IntegrityCheckResult(checked, fixed, unfixable)

Plugs into the check_data_integrity management command and the Celery beat hook that #1188 already wires up. No new periodic task or CLI surface.

Caps

  • Per-request read cap (already shipped in Refactor job logging to use separate table #1259): 1000 rows per response (JOB_LOGS_DEFAULT_LIMIT). UI paginates older entries later.
  • Per-job storage cap: none. Decision in Refactor job logging to use separate table #1259 review — the read cap + an age-based prune is sufficient; per-job ceilings re-introduce the ceiling drift we just removed.
  • Age-based prune: open question. Suggest 30d or 90d default, configurable via setting. Discuss before merging the retention check.

Schedule

Default to manual (--no-dry-run only via the management command) until soak. Wire to beat after one cycle of running it by hand.

Acceptance

Blocked by

Activity

  1. mihow commented on Jun 5, 2026

    @mihow
    CollaboratorAuthor

    Claude says: Surfacing a second check that wants the same shape as this one, in case it's useful when picking the framework conventions (cursor column, umbrella vs per-check beat task, etc.).

    PR #1331 drops the synchronous default_storage.exists() HEAD that the thumbnail generator used to run on every cold-path request. The cached SourceImageThumbnail row is the warm signal we trust now; orphan rows (DB row points at a storage blob deleted out of band) get handed off to a periodic reconciler instead of being caught per-request.

    That reconciler is the same shape as joblog retention here: a get_* over an unbounded child table + a reconcile_* that mutates and returns IntegrityCheckResult. Wants the same cursor-by-last_checked_at pattern once the table grows past sample-friendly size.

    Will open a dedicated Orphan-thumbnail reconciler via data integrity framework (#1188) issue once #1331 lands, modeled on this one. Mirroring the note on #1188 so the framework PR sees both follow-ups lining up the same way.

    Cross-ref: #1188, #1331.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions