Skip to content

Migrate remaining worker/saga in-memory state stores to Redis #190

Description

@balisdev

Owner: whoever owns event-ingestion/disputes (unassigned) · Priority: Low-medium, can be split into per-store PRs — does not block rollout of the Redis approach elsewhere, except EventProcessorService/LedgerCursorService's reorg-safety semantics should be explicitly re-verified as part of their migration.

Description

Beyond the services named in the original persistence spike (#181), the inventory in backend/PERSISTENT_STORAGE_SPIKE.md (§1) found several more process-local Map stores backing background workers, sagas, and run-history tracking:

  • DisputeSagaService (src/dispute/dispute-saga.service.ts) — Map<sagaId, DisputeSaga> + Map<escrowId, sagaId> index. Losing state mid-saga on restart leaves a dispute stuck between steps.
  • EventProcessorService (src/event-ingestion/event-processor.service.ts) — Map<eventId, ProcessedEvent>, the reorg-safety dedup log gating whether a Soroban event has already been processed. Losing it on restart risks double-processing events ingested just before the restart.
  • LedgerCursorService (src/event-ingestion/ledger-cursor.service.ts) — Map<contractId, LedgerCheckpoint>. Already prefixes its Map keys with ledger_cursor:, i.e. it's already shaped like a Redis key — looks like an unfinished migration.
  • ReputationScoreStore (src/reputation/reputation-score.store.ts) — Map<address, ReputationScoreRecord>. Simple KV shape, lowest risk of the group.
  • EscrowReconciliationStateStore (src/escrow-reconciliation/escrow-reconciliation-state.store.ts) — Map<runId, ReconciliationRun>, sorted by start time for listing.
  • MigrationStateStore (src/migration/migration-state.store.ts) — Map<runId, MigrationRun> + Map<migrationName, activeRunId>. Notably, the framework that runs schema migrations currently has no persistent record of having run one.

All six are simple KV/small-index shapes with no unusual query needs — same recommendation as the rest of the spike: Redis, following the pattern GigService's prototype in #181 establishes (entity as SET/GET, indices as sets/sorted sets, transaction-result verification, fallback metric, production fail-fast, graceful fallback to memory otherwise on Redis errors logged at error level).

Tasks

  • Migrate each store to Redis following the GigService pattern (can land as separate PRs per store, or grouped — whichever keeps each PR reviewable)
  • For EventProcessorService and LedgerCursorService specifically: verify the migration preserves reorg-safety semantics (no gap where an event could be double-processed or a cursor lost between the old and new store)
  • Update each store's callers for any resulting async signature changes

Acceptance Criteria

  • Each store's state survives a process restart
  • Multiple backend instances observe the same state for each
  • Existing tests for each affected service still pass, updated for the new store
  • event-processor/ledger-cursor migration is explicitly verified not to weaken reorg-safety guarantees

Estimated Time

3-4 days (spans six stores; may be split into smaller PRs)

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