A real-time matchmaking system built with Elixir and GraphQL that pairs users based on their skill rankings.
Queue of Matchmaking is a skill-based matchmaking system that:
- Accepts user requests to join a matchmaking queue
- Pairs users with similar skill rankings
- Notifies matched users in real-time through GraphQL subscriptions
- Maintains data integrity during concurrent operations
- Stores all data in-memory for fast processing
- Elixir - Primary programming language
- Phoenix - Web framework
- Absinthe - GraphQL implementation
- ETS - In-memory storage
- Install dependencies:
mix deps.get
- Start the Phoenix server:
mix phx.server
The GraphQL endpoint will be available at http://localhost:4000/graphql
Use the addRequest
mutation to add a user to the matchmaking queue:
mutation {
addRequest(userId: "Player123", rank: 1500) {
ok
error
}
}
Response on success:
{
"data": {
"addRequest": {
"ok": true,
"error": null
}
}
}
Get the current state of the matchmaking queue:
query {
queueStatus {
userId
rank
}
}
Response:
{
"data": {
"queueStatus": [
{
"userId": "Player123",
"rank": 1500
},
{
"userId": "Player456",
"rank": 1550
}
]
}
}
Get the history of completed matches:
query {
matchHistory(limit: 5) {
timestamp
users {
userId
rank
}
}
}
Response:
{
"data": {
"matchHistory": [
{
"timestamp": 1703001234,
"users": [
{
"userId": "Player123",
"rank": 1500
},
{
"userId": "Player456",
"rank": 1480
}
]
}
]
}
}
Subscribe to match notifications for a specific user:
subscription {
matchFound(userId: "Player123") {
users {
userId
rank
}
}
}
When a match is found, subscribers receive:
{
"data": {
"matchFound": {
"users": [
{
"userId": "Player123",
"rank": 1500
},
{
"userId": "Player456",
"rank": 1480
}
]
}
}
}
The system uses an expanding window approach to create fair matches:
- Initial matching attempts to find users within ±10 rank points
- If no match is found, the range expands by 90 points each iteration
- Maximum rank difference allowed is 500 points
- Users are paired with the closest available match within the current range
This approach balances match fairness with queue times:
- Quick matches for players when similarly ranked opponents are available
- Gradually relaxed requirements to prevent excessive wait times
- Hard limit on rank difference to prevent highly mismatched games
- Uses ETS tables for in-memory storage:
matchmaking_queue
: Ordered set for active queue (sorted by rank)matches
: Set for completed match history
- Protected access for data integrity
- Efficient rank-based matching using ETS ordered sets
- GenServer manages state and synchronizes operations
- ETS provides atomic operations for queue management
- Phoenix PubSub handles real-time notifications
- Absinthe manages subscription state
Key configurations (in lib/queue_of_matchmaking/matchmaking_queue.ex
):
@initial_rank_window 10 # Initial search window (±10)
@rank_window_increment 90 # Window expansion per iteration
@max_rank_window 500 # Maximum allowed rank difference
These values can be adjusted to balance match quality vs. queue times.
Run the test suite:
mix test
Tests cover:
- Queue operations
- Match processing
- GraphQL mutations and queries
- Real-time subscriptions
- Concurrent request handling
- Edge cases and validation
To start development:
- Clone the repository
- Install dependencies with
mix deps.get
- Start Phoenix endpoint with
mix phx.server
- Visit
http://localhost:4000/graphiql
for interactive GraphQL explorer
MIT License - See LICENSE file for details