Handler: retention.downsample
Keeps recent raw rows, aggregates older rows into a coarser rollup table, then deletes the raw rows the rollup now represents. Classic time-series pattern — useful for gpu_metrics, future pipeline_metrics, any high-frequency append-only table where you want long history but not long-at-full-fidelity history.
Row configuration
downsample_rule JSONB shape
avg, min, max, sum, count. Additional functions require extending the whitelist in services/integrations/handlers/retention_downsample.py.
Allowed intervals: a positive integer and a unit from second/minute/hour/day/week/month/year (singular or plural). E.g. "30 minutes", "1 day".
Precondition: rollup table must exist
The handler does not auto-create the rollup table. Every rollup schema decision (indexes, PK onbucket_start, column types) is a deliberate choice the operator should make. Create the table explicitly before enabling the policy:
as aliases in aggregations. The handler’s INSERT assumes bucket_start is the unique constraint for ON CONFLICT DO NOTHING — so overlapping invocations don’t double-insert.
Operator runbook
Enabling gpu_metrics (seeded, disabled by default)
How the handler works
- Count raw rows older than
keep_raw_days. If zero, short-circuit. - Insert aggregated buckets into
rollup_tableusingdate_trunc('hour', age_column)as the bucket key.ON CONFLICT (bucket_start) DO NOTHINGmakes overlapping runs safe. - Delete raw rows older than
keep_raw_days.
ON CONFLICT DO NOTHING on the existing bucket and proceed to step 3’s delete. Idempotent.
Related
- Framework overview: Integrations
- Sibling handler:
retention.ttl_prune - GH-110 (retention framework issue)