Files
skills/docs/api-stack/api/api-audit-file/src/retention/retention.md
2026-05-29 08:20:56 +01:00

68 lines
2.4 KiB
Markdown

# `retention`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Enforces the `maxFiles` retention dimension of the rotation policy by
deleting the oldest rotated files until at most `maxFiles` remain.
Retention runs immediately after each rotation succeeds so the disk
footprint is bounded across long-running deployments — an audit
directory left to grow unchecked is the most common operator pain
point with file-based sinks, and this module's existence is exactly
the answer to it.
The increment on `api.audit.rotation_evicted_total{sink="file"}` makes
eviction observable. Operators alert on an unexpectedly high rate so a
runaway rotation cycle (e.g. clock skew, misconfigured `maxAgeMs`) is
visible before the retention sweep drops historical data.
## Features
- `enforceRetention(fs, basePath, maxFiles, instruments)` — deletes
the oldest rotated files until at most `maxFiles` remain. Idempotent:
re-running with no surplus is a no-op.
- Counter increment per deletion with the canonical `sink="file"`
attribute set.
- Surfaces `AUDIT_FILE.RETENTION_FAILED` on a delete failure with the
offending path in `context.path` and the underlying `cause`.
## Usage: Basic
```ts
import { enforceRetention } from "@suaveplan/api-audit-file/retention";
await enforceRetention(fs, "/var/log/audit.log", 30, instruments);
```
## Usage: Advanced
Call from a custom rotation cadence — e.g. an external cron that wants
to prune without rotating:
```ts
import { enforceRetention } from "@suaveplan/api-audit-file/retention";
// Cron job: every hour, prune to a smaller retention than the sink's
// default to claw back disk during high-traffic windows.
setInterval(async () => {
await enforceRetention(fs, basePath, 10, instruments);
}, 60 * 60 * 1000);
```
## API Reference
- `enforceRetention(fs: FsAdapter, basePath: string, maxFiles: number, instruments: AuditFileInstruments): Promise<void>`
## Implementation Notes
`listRotatedFiles` returns paths sorted oldest-first by the embedded
ISO timestamp; we slice off the first `(count - maxFiles)` entries and
unlink them. Sorting is lexicographic on the ISO string, which is also
chronological for the `YYYY-MM-DDTHH-MM-SS.sssZ` shape — no extra
parsing required. If `unlink` fails midway, the previously-evicted
deletions are not undone; the throw surfaces the failure and the next
rotation re-attempts retention against whatever survived.