# 3 — Match Service: Geo-Partitioned Distributed Ranking **Rank 3 of 28** · Tier S · `app/MatchService` **Stack:** Go, Cassandra / ScyllaDB (gocql + gocqlx), Redis + Redis Streams, Kafka (segmentio/kafka-go), WebSocket, Zap **Status:** Running. Two production distributed-systems defects found, fixed, and documented in-source. > **Why this ranks here.** This project contains the two best *stories* in the > entire tree. Both are textbook distributed-systems failures that only appear > under real load, in real clusters, with real consumer groups — the kind an > interviewer cannot tell you were rehearsed, because the fix is committed with > the reasoning above it. --- ## What it is The candidate-generation and ranking pipeline: a geo-partitioned Cassandra table of match cards, ranking pipelines that write scores back, a "sorting hat" that indexes ranked cards into discovery decks, a fan-out worker, a Redis Streams feed index, and a WebSocket hub for realtime match delivery. ``` ┌──────────── Kafka ───────────┐ ▼ │ match_engine → match_ranker → SortingHat → discovery decks │ │ │ ▼ ▼ ▼ Cassandra dating_global.match_cards Redis Streams PARTITION (service_region, geohash4) feed_index:writes │ │ ▼ ▼ match_fanout ──────► match_wss_hub ──────► clients ``` ## War story #1 — the phantom partition **`user_partition.go`** `dating_global.match_cards` is partitioned by `(service_region, geohash4)`. The ranking pipelines write scores back to it — but they iterate a **configured list of regions**, and the region in a pipeline's loop is the *pool being ranked*, not necessarily the pool the user's card actually lives in. Cassandra `UPDATE` is an upsert. So writing with the loop region did not update a row — **it silently created a partition**: one phantom `match_cards` row per user per configured region, carrying only score columns and a null `display_name`. The sorting hat then indexed those phantoms into the discovery tables, putting **nameless cards into real user decks.** The fix is a partition-lookup layer: resolve the user's true partition before writing, never infer it from the iteration context. *Why this is a great story:* it is the single most common Cassandra footgun (upsert-on-write with a wrong partition key), it produced a visible product symptom, and the root cause is three inference steps away from that symptom. ## War story #2 — the leaking pending-entries list **`stream_reclaim.go`** A Redis consumer group moves a message into the consumer's **pending-entries list (PEL)** on delivery and removes it only on `XACK`. Both feed consumers `continue` past a processing failure without acknowledging — which is *correct*; acknowledging a message you failed to process throws the data away. But nothing ever came back for those entries. They accumulated. At the time of the fix, `feed_index:writes` held **952 pending messages**, the oldest long past any useful age. The fix is an explicit reclaim path: `XAUTOCLAIM`-style recovery of aged pending entries, so failed work is retried rather than orphaned. *Why this is a great story:* it demonstrates you understand that at-least-once delivery is not free — somebody has to own the retry, and if nobody does, the queue silently becomes a graveyard. ## Other substance - **`match_pair_gate.go`** + test — the mutual-match invariant, gated so a pair cannot be created twice from both sides concurrently. - **`conversation_id.go`** + test — deterministic conversation identity so two services independently derive the same id. - **`exclusion.go`** + test — seen/blocked exclusion sets at candidate-generation time. - **`rank_encoding.go`**, **`ranking_vocab_test.go`** — score encoding stability. - **`match_path_integration_test.go`** — end-to-end path coverage. - **`match_redis_adapter.go`**, **`match_kafka_adapter.go`** — adapters isolating the transport from the engine. ## Scope | Metric | Value | |---|---| | Go source | 33,638 lines, 51 files | | Test files | 7, all targeting invariants rather than surface | | Datastores | Cassandra/Scylla, Redis + Streams, Kafka | | Partition key | `(service_region, geohash4)` | | Documented production defects fixed | 2, with root-cause write-ups in-source | ## Interview surface this opens - Cassandra partition key selection, and why upserts make a wrong key invisible - Geohash-based geo-sharding: precision vs partition size vs cross-cell queries - Redis Streams consumer groups vs Kafka consumer groups — PEL, XACK, XAUTOCLAIM - Retry ownership in at-least-once systems, and dead-letter design - Deterministic id derivation across services without coordination