Skip to content

Commit 7a66578

Browse files
ibrahimMaryam-techibrahimchokkoclaude
authored
feat(backend): implement horizon failover, transaction index, auth rate limiting, and soroban event streamer (#1073)
- #947: StellarClient keeps a sticky primary plus backup RPC endpoints (STELLAR_RPC_BACKUP_URLS). Timeouts, connect errors, 5xx and 429 put the endpoint on a 30s cooldown and fail over immediately to the next healthy one; backoff applies only after a full pass over the pool. - #948: Concurrent (zero-downtime) compound indexes on yield_transactions(user_id, created_at DESC) and payments(sender_id|receiver_id, created_at DESC), one per no-transaction migration, plus rollback scripts. The schema has no `transactions` table or `user_address` column, and the already-applied 20260728000000 migration is left untouched to avoid a sqlx checksum mismatch. - #949: Auth rate limiter is now a sliding window (10 req/min/IP) backed by an atomic Redis sorted-set Lua script, falling back to an in-process sliding window when Redis is unset or unreachable. 429 responses carry Retry-After. - #950: indexer::soroban polls getEvents (via the failover client), decodes events with the indexer parser, and fans them out over a tokio broadcast channel to WebSocket clients at /api/events/ws. Lagging consumers skip ahead instead of blocking the producer. Enables axum "ws". Co-authored-by: maryam <ipcymuhammad1@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 24a5558 commit 7a66578

14 files changed

Lines changed: 1196 additions & 102 deletions

‎backend/Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2021"
66
[workspace]
77

88
[dependencies]
9-
axum = { version = "0.7.4", features = ["multipart"] }
9+
axum = { version = "0.7.4", features = ["multipart", "ws"] }
1010
tokio = { version = "1.36.0", features = ["full"] }
1111
serde = { version = "1.0.197", features = ["derive"] }
1212
serde_json = "1.0.114"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
-- no-transaction
2+
-- #948: Zero-downtime compound index for per-user transaction history
3+
-- (`WHERE user_id = $1 ORDER BY created_at DESC`).
4+
--
5+
-- CREATE INDEX CONCURRENTLY cannot run inside a transaction block, so the
6+
-- `-- no-transaction` directive above (must be the first line; sqlx 0.7
7+
-- syntax) tells SQLx not to wrap this file. Postgres also runs a
8+
-- multi-statement query string as one implicit transaction, so each
9+
-- concurrent index lives in its own migration file.
10+
--
11+
-- If a concurrent build is interrupted it leaves an INVALID index that
12+
-- IF NOT EXISTS will skip; drop it with DROP INDEX CONCURRENTLY and re-run.
13+
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_yield_tx_user_id_created_at
14+
ON yield_transactions (user_id, created_at DESC);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- no-transaction
2+
-- #948: Zero-downtime compound index for a user's sent-payment history
3+
-- (`WHERE sender_id = $1 ORDER BY created_at DESC`). See
4+
-- 20260924000000_add_yield_transactions_user_created_at_index.sql for why
5+
-- this runs outside a transaction and in its own file.
6+
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_payments_sender_id_created_at
7+
ON payments (sender_id, created_at DESC);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- no-transaction
2+
-- #948: Zero-downtime compound index for a user's received-payment history
3+
-- (`WHERE receiver_id = $1 ORDER BY created_at DESC`). See
4+
-- 20260924000000_add_yield_transactions_user_created_at_index.sql for why
5+
-- this runs outside a transaction and in its own file.
6+
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_payments_receiver_id_created_at
7+
ON payments (receiver_id, created_at DESC);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-- Rollback for 20260924000000_add_yield_transactions_user_created_at_index.sql
2+
-- Run outside a transaction (psql -f does not wrap by default).
3+
DROP INDEX CONCURRENTLY IF EXISTS idx_yield_tx_user_id_created_at;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-- Rollback for 20260924000001_add_payments_sender_created_at_index.sql
2+
-- Run outside a transaction (psql -f does not wrap by default).
3+
DROP INDEX CONCURRENTLY IF EXISTS idx_payments_sender_id_created_at;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-- Rollback for 20260924000002_add_payments_receiver_created_at_index.sql
2+
-- Run outside a transaction (psql -f does not wrap by default).
3+
DROP INDEX CONCURRENTLY IF EXISTS idx_payments_receiver_id_created_at;

0 commit comments

Comments
 (0)