Allow to limit the number of rooms a process can spawn
To prevent the process from consuming too much CPU and slowing down all of its spawned rooms, it would be best to have a way to limit the number of rooms a process can spawn.
(https://discuss.colyseus.io/topic/11/about-setting-number-of-rooms-for-a-registered-room-on-the-server/4)
Hi Endel
Any updates on this one ?
Syntax suggestion by @oyed
gameServer
.define('my-room', MyRoom)
.filterBy(['id'])
.maxInstances(1);
Use-case for context:
gameServer.define('my-room', MyRoom).filterBy(['id']).maxInstances(1)
maxInstances will take in to account any filters defined by filterBy to determine a count of existing Room Instances. Using the Room definition above:
Client A: .joinOrCreate('my-room', { id: 123 }): Succeeds in creating and joining the Room, then makes it private/locks it
Client B: .joinOrCreate('my-room', { id: 123 }): Fails and the Promise is rejected (Previously created instance is private, and only 1 instance can exist with the same id option)
Client C: .joinOrCreate('my-room', { id: 456 }): Succeeds in creating and joining the Room
Did this ever get addressed?
Hi @LukeWood,
It was not addressed yet. @MateusMendesSantana did propose a solution in the past that should work on single-process environments.
I believe a modified version of that could suit environments with more processes as well. This hasn't been prioritized because when you use multiple processes, new rooms are created on the process with the least amount of rooms spawned. Adding more processes will make sure the load is distributed among them.
The feature is still valuable if all available processes are "full", though. So the game doesn't become unplayable due to competing CPU usage.
This won't land on 0.15 yet, but it's an interesting feature to land later!
I'm expecting the server to throw a MatchMakeError with a special error code for the client when the "create" request can't be handled by any of the available processes - so the client can display a proper error message for the user.
Thanks for the information @endel ! I'll see what I can do on my end, and then let you know how I solve the problem!
So to move forward with the proposed solution n @endel do we need to use Redis?
This is a very hard problem to solve. When you have multiple users hitting different servers at the same time, they both try to create the room at the exact same time.
You'd need some form of interlocking, using REDIS to get a semaphore value for room creation. But, you can't keep that semaphore for very long, because room creation can take some time. So, you've got to create a placeholder room in redis, that lets other servers know that the room is being created. But since the room doesn't exist, it can't necessarily direct players to it just yet. You need a mechanism for all of those players to wait for the room creation to complete, and then they can join.
Honestly, we really need single instance rooms, too. But we don't need colyseus to change to do it.
One approach:
- Instead of doing
joinOrCreate, use matchmaker data - check if room exists in matchmaker data
- if exactly one does great, send roomId to client, and client joins
- if more than one does, select the one that was created first, and return to client.
- If it does not, create the room. Put a timestamp in metadata (if we cannot access creation timestamp)
- wait for room creation to complete
- check for duplicate rooms. If multiple rooms were created, select the one created first and return to client
- destroy room that was not selected, if necessary
Easier approach:
- check for other rooms during onCreate of the room itself.
- Use a dedicated redis entry for the "filterBy" data, and using HINCR on REdisPresense as a semaphore, and throw if room already exists.
- client would need to catch the thrown error and retry joining. When it retries, it should find the room that already exists.
In our project, we actually implement this using RedisPresence now in the room onCreate. Using hincrby we can do an interlocked update and check result to determine if the max number of rooms for it's type is created and we THROW if the count is exceeded (need to hincrby to undo the first in this case)