juspay / juspay/decision-engine
Sticky routing: Redis storage layer — per-customer net habit counts
- Dominant language
- Rust
- Stars
- 128
- Forks
- 36
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 34
Description
Part of #393 (sticky routing). **Status: implemented** in #419 (commit `575d249`), pending review/merge.
One Redis hash per `(merchant, customer)` holds the customer's NET habit counts — successes add one, gateway failures subtract one (floored at zero; failures never create a key or field, and only positive counts qualify as pin candidates):
```
Key: sticky_gw_{merchant_id}_{customer_id} (ids trimmed, case preserved)
Field: {PM}:{PMT}:{connector} (PM/PMT case-folded, connector verbatim)
Value: integer net count (+1 success, -1 failure, floor 0) (HINCRBY — atomic under concurrent feedback)
```
Example: `sticky_gw_m1_cust42` → `{ "INTERAC:RTP:GIGADAT": 3, "INTERAC:RTP:LOONIO": 2 }`. Listpack-encoded: **136 B** for a typical 2-combo customer, **952 B** at the 30-combo cap (measured on Redis 7.2.7) — ~150–250 MB per 1M active customers.
Eviction safety (sticky keys must never crowd out SR/elimination state):
1. **Sliding TTL** on every hash, re-armed in the same MULTI as the write (`STICKY_ROUTING_KEY_TTL`, default 90 days). Idle customers self-evict; every key stays volatile.
2. **Per-customer combo cap** (`STICKY_ROUTING_MAX_COMBOS_PER_CUSTOMER`, default 30): a new field over the cap prunes the lowest-count fields (full excess drains), keeping the hash listpack-encoded.
3. **Per-merchant admission budget** (`STICKY_ROUTING_MAX_CUSTOMERS_{mid}`, default 1M new hashes per TTL window, tracked by two-window counters `sticky_gw_adm_{mid}_{window}` with TTL 2×window): once spent, existing customers keep updating but no new keys are created — growth bounded up front, no reliance on Redis eviction.
New wrapper commands on `RedisConnectionWrapper`: `hincrby_with_expire` (MULTI: HINCRBY+EXPIRE so a hash can never exist without a TTL), `hgetall_map`, `hdel_field`. Module: `src/sticky_routing.rs`.
Contributor guide
Assessment
This issue has not been assessed yet.