Skip to content

feat: harden session compaction job with retention policy - #794

Open
Bouynaty wants to merge 1 commit into
RevoraOrg:masterfrom
Bouynaty:feat/session-compaction-job
Open

feat: harden session compaction job with retention policy#794
Bouynaty wants to merge 1 commit into
RevoraOrg:masterfrom
Bouynaty:feat/session-compaction-job

Conversation

@Bouynaty

Copy link
Copy Markdown

Overview

This PR hardens the nightly Session Storage Compaction job so that revoked and expired session rows are deleted only after they have truly aged past the retention window, the table is vacuumed to reclaim space, and operators get actionable signals if a compaction run is under pressure.

Related Issue

Closes #683

Changes

🛡️ Bad-clock safe retention boundary

  • [MODIFY] src/db/repositories/sessionRepository.ts
    • purgeOlderThan(retentionDays, batchSize) now computes the retention boundary inside the database (NOW() - retention * INTERVAL '1 day') instead of accepting an application-server timestamp.
    • getOldestCompactedSessionDate(retentionDays) uses the same DB-clock boundary so the retention-lag metric stays consistent with the purge predicate.
    • Active sessions (future expires_at, no revoked_at) can never match the delete predicate — even during a bad-clock event on the app server.

🧱 Bounded blast radius

  • [MODIFY] src/services/sessionCompactionService.ts
    • Added a per-run row cap (SESSION_COMPACTION_MAX_ROWS_PER_RUN, default 100_000) so an anomaly can never wipe the table in a single cycle; remaining rows stay behind for the next run.
    • Emits session.compaction.cap_hit (counter, status=warning) when the cap is reached.
    • Validates batchSize / maxRowsPerRun (positive integers) before touching the DB.
    • Scheduled-run and initial-run failures are logged without killing the timer.

⚙️ Configuration

  • [ADD] src/config/env.ts
    • SESSION_COMPACTION_MAX_ROWS_PER_RUN — max rows a single compaction run may delete (default 100000).

🧪 Tests & 📄 Docs

  • [MODIFY] src/services/sessionCompactionService.test.ts — bad-clock safety, per-run cap enforcement, batch draining, error metrics, input validation, and start/stop lifecycle.
  • [MODIFY] src/db/repositories/sessionRepository.test.ts — purge predicates (DB-clock boundary, active-row exclusion) and lag query.
  • [ADD] docs/session-storage-compaction.md — design doc with security assumptions and failure-path analysis.

Verification Results

npx jest src/services/sessionCompactionService.test.ts src/db/repositories/sessionRepository.test.ts --coverage --collectCoverageFrom=src/services/sessionCompactionService.ts
✅ 49/49 passed

Coverage (sessionCompactionService.ts):
  Statements: 100%
  Branches:   86.2%  (repo gate: 80%)
  Functions:  100%
  Lines:      100%
Acceptance Criteria Status
Revoked/expired rows older than retention are deleted nightly ✅ Batch-deletion loop with bounded LIMIT batches
Table is vacuumed after deletion VACUUM sessions on its own connection, only when rows were deleted
Metrics for rows compacted session.compaction.rows counter
Metrics for lag from retention boundary session.compaction.retention_lag_days histogram
Batch cap prevents deleting active rows during a bad-clock event ✅ DB-computed NOW() boundary + per-run row cap; active rows can never match the predicate
Minimum 95% test coverage ✅ 100% statements/lines/functions on the service

Timeline

  • Branch feat/session-compaction-job created from upstream master.
  • Fix implemented, tests extended, documentation added.
  • Author and committer: Bouynaty <Bouynaty@users.noreply.github.com>.

Refine the nightly session compaction job so the retention boundary is computed inside the database (NOW() - retention interval) rather than passed in from the application-server clock. A bad-clock event on the app server can no longer push the boundary forward and cause active rows to be deleted.

Add a per-run row cap (SESSION_COMPACTION_MAX_ROWS_PER_RUN, default 100k) so an anomaly can never wipe the table in one cycle; emit session.compaction.cap_hit when the cap is reached. Validate batch and cap inputs, and log scheduled-run failures without killing the timer.

Tests cover batched deletion, vacuum behavior, error metrics, bad-clock safety, cap enforcement, input validation, and the start/stop lifecycle (100% statement coverage on the service).

Closes RevoraOrg#683
@drips-wave

drips-wave Bot commented Jul 31, 2026

Copy link
Copy Markdown

@Bouynaty Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Bouynaty

Bouynaty commented Aug 2, 2026

Copy link
Copy Markdown
Author

@thlpkee20-wq done closes #683

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.

Session storage compaction job trimming revoked rows older than retention

1 participant