Skip to content

feat(backend): per-network ledger cursor, gap alerts, reindex reset - #250

Merged
jhayniffy merged 2 commits into
InsurNiffy:mainfrom
favourawaku:feat/ledger-cursor-indexer
Mar 29, 2026
Merged

feat(backend): per-network ledger cursor, gap alerts, reindex reset#250
jhayniffy merged 2 commits into
InsurNiffy:mainfrom
favourawaku:feat/ledger-cursor-indexer

Conversation

@favourawaku

Copy link
Copy Markdown
Contributor

Summary

closes #213
Adds a per-network ledger cursor so the Soroban indexer can resume after restarts or RPC outages without reprocessing from genesis or skipping ledgers. Cursor updates are atomic with event upserts. Gap detection alerts when the chain head pulls too far ahead of the cursor, with cooldown-based deduplication. Admin reindex resets the cursor and enqueues a BullMQ catch-up job.

Changes

Database

  • ledger_cursors: network (PK), last_processed_ledger, updated_at.
  • ledger_gap_alert_dedup: last gap alert time per network (cooldown / storm prevention).
  • Migration backfills testnet from legacy indexer_state where present.

Indexer

  • Reads/writes cursor keyed by STELLAR_NETWORK (default testnet).
  • last_processed_ledger updated inside the same Prisma transaction as raw_events + projection writes.
  • Gap alert when latestLedger - lastProcessed > INDEXER_GAP_ALERT_THRESHOLD_LEDGERS (default 100); repeats only after INDEXER_GAP_ALERT_COOLDOWN_MS (default 1h).
  • ReindexWorkerService: processes reindex queue → processUntilCaughtUp (off in NODE_ENV=test or DISABLE_REINDEX_WORKER=1).
  • Fixes corrupted handleClaimFiled and vote payload handling.

Admin API

  • POST /admin/reindex: optional network; sets last_processed_ledger = max(0, fromLedger - 1), enqueues job, audit includes network + jobId.

Claims

  • getLastLedger uses ledger_cursors for the configured network, with indexer_state fallback.

Config

  • STELLAR_NETWORK, INDEXER_GAP_ALERT_THRESHOLD_LEDGERS, INDEXER_GAP_ALERT_COOLDOWN_MS in env.validation.ts.

Tests & tooling

  • Specs for cursor resume, cursor-in-transaction, gap dedupe, reindex cursor + controller.
  • jest.config.js: include **/*.spec.ts.
  • Idempotency middleware: correct Redis import path; fail-open on idempotency lookup errors.

Deploy notes

Run npx prisma migrate deploy (or equivalent) before starting workers.

Testing

npm test and npm run build in backend/.

- Add ledger_cursors (network PK, last_processed_ledger, updated_at) and
  ledger_gap_alert_dedup for cooldown-based gap notifications
- Indexer advances cursor inside same Prisma tx as raw_events + projections
- Gap alert when latestLedger - lastProcessed > threshold; dedupe via cooldown
- Admin POST /admin/reindex resets cursor (fromLedger-1), enqueues Bull job;
  ReindexWorkerService runs processUntilCaughtUp (disabled in test / DISABLE_REINDEX_WORKER)
- STELLAR_NETWORK + INDEXER_GAP_ALERT_* env; ClaimsService reads cursor by network
- Migration seeds testnet row from legacy indexer_state
- Tests: cursor resume, tx-bound advance, gap dedupe, admin reindex
- Fix idempotency middleware Redis import path + fail-open on lookup errors
- Jest: include *.spec.ts in testMatch

Made-with: Cursor
@drips-wave

drips-wave Bot commented Mar 27, 2026

Copy link
Copy Markdown

@favourawaku 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

@jhayniffy
jhayniffy merged commit 9dd505f into InsurNiffy:main Mar 29, 2026
2 of 7 checks passed
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.

Backend — Ledger cursor persistence: resumable indexer with gap detection

3 participants