Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to limit the number of rooms a process can spawn #155

Open
endel opened this issue May 18, 2018 · 9 comments
Open

Allow to limit the number of rooms a process can spawn #155

endel opened this issue May 18, 2018 · 9 comments
Assignees
Milestone

Comments

@endel
Copy link
Member

endel commented May 18, 2018

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)

@endel endel added this to the 0.9.x milestone May 18, 2018
@TyrusShan
Copy link

Hi Endel

Any updates on this one ?

@endel endel modified the milestones: 0.9.x, 1.0.x Aug 22, 2018
@endel endel self-assigned this Mar 19, 2019
@endel
Copy link
Member Author

endel commented Nov 1, 2019

Syntax suggestion by @oyed

gameServer
  .define('my-room', MyRoom)
  .filterBy(['id'])
  .maxInstances(1);

@oyed
Copy link
Contributor

oyed commented Nov 1, 2019

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

@LukeWood
Copy link
Contributor

Did this ever get addressed?

@endel
Copy link
Member Author

endel commented Apr 12, 2023

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.

@LukeWood
Copy link
Contributor

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!

@LukeWood
Copy link
Contributor

So to move forward with the proposed solution n @endel do we need to use Redis?

@hunkydoryrepair
Copy link
Contributor

hunkydoryrepair commented Nov 3, 2023

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.

@hunkydoryrepair
Copy link
Contributor

hunkydoryrepair commented Jan 12, 2024

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants