Design Online Chess Matchmaking
Company: OpenAI
Role: Software Engineer
Category: System Design
Difficulty: hard
Interview Round: Technical Screen
Design the backend architecture for an online chess platform's matchmaking system.
Players submit requests to play ranked or casual chess games. A request may include the player ID, current rating, desired time control, region or latency constraints, client version, and optional preferences such as avoiding recent opponents. The system should pair players with compatible skill and acceptable latency, while gradually widening the search criteria as a player waits longer.
### Constraints & Assumptions
Treat the following as working assumptions; if the interviewer hasn't specified them, state your own and proceed.
- Multiple concurrent queues exist, split by mode (ranked, casual), time control (bullet, blitz, rapid, classical), and region.
- Player rating is an integer (e.g. Elo/Glicko-style) used to gauge skill compatibility; ratings are bucketed (for example, every 100 points).
- Popular queues can hold far more waiting players than quiet ones, so load is highly skewed across queue keys ("hot" vs. "cold" buckets).
- A player should never be matched into two games at once, and a retried request must not create a duplicate queue entry.
- Wait time, not just match quality, matters: a player who has waited longer should be paired sooner, even at the cost of a looser match.
### Clarifying Questions to Ask
- What is the expected scale (peak concurrent players in queue, requests per second) and the target p95/p99 time-to-match per queue?
- How strict is match quality versus wait time? Is there a maximum acceptable wait before we relax skill/region constraints, or a hard timeout?
- Are ratings authoritative elsewhere (a separate rating/player service), or does matchmaking own them?
- What notification transport is available to tell both clients a match was found (persistent WebSocket, push, polling)?
- How should disconnects and reconnects during queueing be treated — keep the request alive with a grace period, or cancel immediately?
- Is repeat-opponent avoidance a hard constraint or a soft preference?
Address the following areas in your design:
### 1. Service decomposition: match request handler vs. matchmaking service
Explain why the match request handler and the matchmaking service should be separate services, including how their responsibilities and scaling characteristics differ.
```hint What differs between them
Compare what each component does on the request path versus in the background, and how each one needs to **scale**. One is driven by API traffic; the other by queue depth and matching cost.
```
```hint Latency coupling
Think about what happens to client-facing API latency if a single service both accepts requests *and* runs a long-running scan/matching loop in the same process.
```
### 2. Queueing and mapping requests to matchmaking workers
Describe how match requests are queued and how those queues are mapped to matchmaking workers. Address what the queue is keyed by and how you avoid both single-queue bottlenecks and many workers contending over the same queue.
```hint How to key a queue
Consider composing a queue key from the request's attributes (mode, time control, region, rating bucket) so compatible players land in the same or nearby queues.
```
```hint Storage choice
Weigh an in-memory ordered structure (e.g. a sorted set ordered by enqueue time) against a durable append-only log. What does each give up on latency, durability, and random candidate lookup?
```
```hint Worker assignment
A worker-per-queue mapping doesn't scale, and letting every worker pull from every queue invites contention. What unit smaller than "a service per queue" could you assign to workers instead, how might you map queue keys onto those units, and what would have to coordinate the assignment so each unit has exactly one owner — and so ownership is reclaimed automatically when a worker dies?
```
### 3. Consuming widened bucket queues as wait time increases
Explain how the matchmaking service widens a player's acceptable rating and region range as their wait time grows, and how a worker consumes these widened candidate buckets.
```hint Widening policy
Express the widening as a function of **wait time**: start narrow (same rating bucket, same region), then progressively admit adjacent rating buckets and nearby regions.
```
```hint Where does the widening live
When a request ages, something has to make wider buckets reachable for it. Does that "something" change where the request is stored, or where the worker looks? Sketch more than one way to arrange this, then ask which is harder to keep consistent when the same request could now appear in (or be considered by) several buckets at once.
```
### 4. Player service ownership and its interaction with matchmaking
Describe what the player service owns and how it interacts with the matchmaking service.
```hint Source of truth
Decide which durable, authoritative state lives with the player service (identity, rating, bans/trust, current-game status, presence) versus what matchmaking may merely cache for speed. Who is the source of truth for rating?
```
### 5. Concurrency, duplicates, cancellation, failures, fairness, scalability, observability
Explain how the system handles concurrency, duplicate requests, cancellation, failures, fairness, scalability, and observability.
```hint Concurrency without coarse locks
The dangerous case is two matches claiming the same player at the same time. A broad distributed lock around the whole queue would prevent it but kill throughput — so what cheaper invariants could make a double-claim impossible? Think about who is allowed to mutate a given request at all, and how a single state change on that request could be made to succeed for only one claimant and fail for any racing one.
```
```hint Idempotency and recovery
For duplicates and retries, ask what identifier would let the system recognize "I've already seen this exact request" so a re-send is a no-op rather than a second queue entry. For failures mid-flight, walk the unhappy path: if a claim succeeds but the next step crashes, what stops that player from being stranded out of the pool forever, and what stops a retry of game creation from producing two games?
```
```hint Fairness and observability signals
For fairness, ask what ordering of candidates keeps a long-waiting player from being repeatedly passed over as fresh arrivals stream in. For observability, picture a single queue that has silently gone wrong — too slow, too empty, too strict, thrashing on retries — and ask which numbers you'd need on a dashboard to tell those failure modes apart. Name the signals yourself rather than reaching for a generic "log everything."
```
### What a Strong Answer Covers
```premium-lock What a Strong Answer Covers
```
### Follow-up Questions
- How does this change at 100x scale, when a single popular queue (e.g. ranked blitz in one region) becomes a hot partition that one shard owner can't keep up with?
- What breaks first under load — the queue store, the worker scan loop, game-session creation, or notifications — and how would you detect and shed that pressure?
- How do you prevent a reserved-but-never-finalized match (game-service failure after reservation) from leaving a player stuck out of the pool?
- If a player disconnects after being matched but before the game starts, what is the correct policy, and how do you keep it idempotent across reconnect/retry?
Quick Answer: This question evaluates a candidate's ability to design scalable, low-latency matchmaking backend systems, covering distributed service decomposition, queuing and worker mapping, state ownership, progressive widening of search criteria, and concerns like concurrency, duplicate requests, cancellations, failures, fairness, scalability, and observability. It is commonly asked to assess architectural trade-offs in real-time distributed systems and the capability to apply system design principles to operational requirements; category: System Design; level of abstraction: practical application grounded in conceptual architectural understanding.