Skip to content

feat(db): event retention policy — prune soroban_events older than EVENT_RETENTION_DAYS #135

Description

@Depo-dev

Summary

The soroban_events table will grow without bound for as long as the indexer runs. On testnet this might be tolerable, but on mainnet with busy contracts it will consume disk at a rate that makes self-hosting prohibitively expensive. Operators need a configurable TTL that automatically prunes old events on a schedule.

This is a quality-of-life feature for Phase 2 self-hosted deployments. It does not affect the hosted Trident tier (which will manage retention separately at the infrastructure level), but it is essential for operators running their own instance against a contract with high event volume.

Context

The soroban_events table has a ledger_timestamp column of type TIMESTAMPTZ which is perfect for time-based pruning. The cleanup job should run in the background in the Go API process — it does not need its own service — and should be chunked to avoid holding a long lock that blocks the indexer's inserts.

What needs to be built

A background goroutine in the Go API that:

  • Reads EVENT_RETENTION_DAYS env var at startup (integer, default 0 = disabled)
  • When EVENT_RETENTION_DAYS > 0, starts a ticker that fires every 6 hours
  • On each tick, deletes events in chunks of 1,000 rows at a time using:
    DELETE FROM soroban_events WHERE id IN (SELECT id FROM soroban_events WHERE ledger_timestamp < NOW() - INTERVAL '$N days' LIMIT 1000)
  • Loops the chunked delete until zero rows are returned (all old events pruned)
  • Logs the total rows deleted and wall-clock duration for each cleanup run
  • Handles context cancellation cleanly — stops mid-run if the process is shutting down

Acceptance Criteria

  • When EVENT_RETENTION_DAYS=0 (default), the background job never starts
  • When set, the job runs every 6 hours and deletes in 1,000-row chunks
  • Deletion does not lock the table long enough to block indexer inserts (verified by running both concurrently in integration test)
  • Log line after each run: [retention] pruned N events older than X days in Yms
  • Integration test: seed 50 events with ledger_timestamp set to 10 days ago, trigger retention with EVENT_RETENTION_DAYS=7, assert all 50 deleted

Metadata

Metadata

Assignees

No one assigned

    Labels

    Stellar WaveIssues in the Stellar wave program

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions