This document describes the consistency strategy implemented to prevent quotes from reading pre-commit offer rows during indexer writes.
When the indexer writes new SDEX offers or AMM pool reserves, there's a window where:
- Write transaction has begun but not committed
- Quote endpoint reads from the same tables
- Quote endpoint may see uncommitted or partially committed data (dirty reads)
We implement consistency guards using PostgreSQL transaction isolation levels and visibility rules.
- How it works: Each transaction sees a consistent snapshot of the database from the start
- Benefits: No dirty reads, consistent view throughout transaction
- Trade-offs: May see slightly stale data if write committed after snapshot
- How it works: Explicitly checks for row-level locks before reading
- Benefits: Always sees latest committed data
- Trade-offs: Requires lock detection queries
- How it works: Strictest isolation, detects conflicts automatically
- Benefits: Strongest guarantees
- Trade-offs: Higher chance of transaction conflicts/retries
Located in crates/api/src/consistency_guard.rs:
let guard = ConsistencyGuard::new(
ConsistencyStrategy::SnapshotIsolation,
metrics
);
let mut tx = guard.begin_read_transaction(&pool).await?;
let visible = guard.check_visibility(&mut tx, (base, quote)).await?;Tracked metrics:
guarded_reads: Total number of guarded read transactionsstale_reads_prevented: Number of reads blocked due to ongoing writesconflict_retries: Number of transaction retries due to conflicts
Set via environment variable:
CONSISTENCY_STRATEGY=snapshot # or "version" or "serializable"Regression tests in crates/api/tests/consistency_guard_test.rs reproduce stale-read scenarios and verify guards work correctly.
Run tests:
TEST_DATABASE_URL=postgres://localhost/stellarroute_test cargo test --test consistency_guard_test -- --ignored- Snapshot Isolation: Minimal overhead (~1-2ms per transaction)
- Version Checking: Moderate overhead (~5-10ms for lock checks)
- Serializable: Higher overhead, may require retries
Monitor via Prometheus metrics:
stellarroute_api_consistency_guarded_reads_totalstellarroute_api_consistency_stale_reads_prevented_totalstellarroute_api_consistency_conflict_retries_total