Project
realtime-odds-platform
activeReal-time odds delivery: a sharded WebSocket hub that drops slow consumers, with RabbitMQ queues partitioned by event to keep per-event order (in progress).
go · rabbitmq · websockets
What it is
A real-time odds platform: it ingests event updates from external providers and pushes them to subscribed clients over WebSocket. It comes from a system design problem I was given in a sportsbook interview.
The interesting constraint is ordering: updates for one event must reach the client in order, while updates for different events run in parallel. The WebSocket gateway is working; the ingestion pipeline is in progress.
Architecture
- Ingestion. Providers push updates into N RabbitMQ queues routed by
hash(eventId) % N, with one worker per queue. Each worker writes the new state to Redis and publishes the fragment to Redis Pub/Sub. - Gateway. A client opens
/wsand sendssubscribe(eventId); one connection can follow many events. The hub is sharded byhash(eventId), and each shard maps an event id to its subscribed clients. - Connections. Each connection runs a
readPumpfor client commands and awritePump, the only goroutine that ever writes to the socket.
The repository is a monorepo with two independent services, each with its own Go module and its own hexagon (ports and adapters).
What I learned
The trade-offs from the README’s design notes:
- Hash-partitioned queues give parallelism between events and serialisation within one. Same idea as Kafka partitions, applied to RabbitMQ.
- Sharding the hub means updates for unrelated events never contend for the same lock.
- One write pump per connection, because Gorilla WebSocket connections do not support concurrent writers.
- Non-blocking send. Dropping a slow consumer is deliberate: availability of the fan-out over delivery to one client.
- Redis holds state as well as transporting it, because Pub/Sub has no replay and a client connecting between updates would otherwise see nothing.
What’s next
Finishing the ingestion pipeline, which the README lists as in progress.