I'm using Node.js and Redis. I'm trying to come up with a reliable way to automatch players. There is a matching server and then multiple game servers set up.
The following is what I need to have happen:
- Player sends join request with game type (small/medium etc)
- Matching server adds player to the current game type that is waiting for players
- Game server sends player the game ID
Currently I have implemented this as follows:
- Matching server listens to game:queue:small using BRPOP
- Checks if game:queue:small:id = id exists
- Checks if game:id:users length is <= 6 (max players)
- Adds player to game:id:users list if it is
- If game length is now 6, it removes game:queue:small:id
If the matching server finds game:queue:small:id is missing, it does as follows:
- INCR game:nextGameId
- Sets game:queue:small:id to the previously generated ID
- Adds the game ID to game:queue:waiting
The game servers wait using BRPOP for new games. When they get one, they wait until the game has a minimum of 2 users then start a timer. If they don't fill up in that time, they begin with the users they have and subsequently remove game:queue:small:id (thus forcing the matchmaker to request a new game).
Whilst my method is working, I'm not convinced it will work well in production and it seems very convoluted. I can see the potential for the following issues:
- Game server crashes after accepting the game ID from the waiting list resulting in users getting added to the game:id:users but nothing happening with them (the crash itself isn't a problem, but users continuing to get added to that games queue is)
- If a user disconnects and the game hasn't started, the game server will remove the user from the game:id:users list. Whilst it is in the process of doing that, the matchmaking server could be adding a user to the list and think the game is full, thus removing it from the queue.
My initial thoughts were to change to a single queue of users waiting for one game type. However, this presents further issues:
- If the server that the users connects to crashes, it won't remove the user from the queue thus leaving that user to be entered into a game when they don't exist. I could use sorted sets to store the time of the request and have the client poll until it gets a game ID returned but this would mean that I have no idea of how long that client has waited and therefore do not know whether to start the game with fewer users.
- Without putting the users into a game, they have no ability to see what users have joined, nor the ability to chat with the users that are waiting (as that requires a game ID).
None of the way I have set this up feels right so I was hoping someone might be able to offer some better suggestions. I really need to keep the game servers and the matchmaking servers separate though in order to grow them out as required.