The Django channels tutorial shows how to make a chatroom and how to run a worker. If I used that worker to turn the chatroom into a game, and the worker is tracking game state, then how to I upgrade the website so multiple games can be running at the same time? Can I somehow put a script into the views.py that runs a worker when a chat room is initiated? If the redis server had to track the entire site’s games, then if one game caused an error the entire site would crash.
I have a set of models to track game state. One of those models is a “Player” object identifying the user playing a particular instance of a game.
I suggest you think of these as Channels Groups rather than as “chat rooms”.
Anyway, you can program your Consumer that creates a Group to send a message to the worker when that group is created.
Side note, you’re likely going to want to use something like Channels Presence to track who is connected to the Group. You’ll also want to track this by user and not by channel_name. (Websockets can get interrupted - you’ll want to use a websocket client that will auto-reconnect, and, since a new Consumer instance - with a new channel_name - gets created for each connection, you will not want to track participants by their channel_name.)
Yeah they are groups, but to disambiguate, on the front end there will be multiple “lobbies.” Can I for example have an index of lobbies on my website, and each one has separate consumers+workers? I presume I would at least need a separate worker running for each game-room that is active on the website, so that if one game causes an error the rest can continue running.
The worker already takes care of presence fine. Allowing for players to have statuses of “disconnected,” receiving private game messages, etc…
On the backend, what is a “Lobby”?
This is not necessarily correct. A worker receives messages from the channel layer. It processes the message and returns responses as appropriate. As long as the method handling the message returns, it’ll be ok to handle the next message.
In my case, I have a separate worker per “game title”. For example, I could have a worker for “Tic-Tac-Toe”, another worker for “Rock-Paper-Scissors”, another worker for “Checkers”, etc. (Note, my “Lobby” is just another “game”.) I do it this way only to facilitate adding a new game without affecting the rest of the system. I could just as easily have built this where I have a single worker that calls the different state-machines depending upon the message received.
I don’t know if you are using workers the same way as me. Because like I said I use mine for presence and game state and player actions.
A lobby is the chat room found in the Django-Channels tutorial, plus a worker that is practically an invisible bot in the chat-room that: tracks presence; tracks whether lobby capacity has filled; sends game updates, sometimes as messages, sometimes as DOM manipulation; and tracks game state.
Methods in the worker for sending private/public game updates:
def message(self, event):
async_to_sync(self.channel_layer.send)(
event["player_channel"],
event,
)
def group_message(self, event):
async_to_sync(self.channel_layer.group_send)(self.group, event)
Upon first player connecting via websocket on the website, the worker notes their presence, and the worker is assigned to the channel layer group that player is in. Hence the “self.group” in the group_message method. So I could rework it to do otherwise, but then the worker crashing would bring down the website, no? Otherwise, I copy and paste the worker code so there are 10 of them, run 10 workers, and bam my site can have 10 games running.
I’m using “worker” as what is defined in the Channels docs
Unfortunately, I’m not sure I’m following what you mean by “worker” here. What you’re showing looks like standard parts of a consumer.
A chat room in the tutorial is just a Channels group - which as implemented with the redis back end is a redis key with a list of connected channel names. It’s not an independent entity within your Django project.
A Channels worker shouldn’t crash, unless you’re doing something fundamentally wrong, in which case you need to fix the worker.
The channels worker is a SyncConsumer running on a redis server. Whenever a user connects to the chat room the worker is sent a message with their username and group.
Your examples of workers don’t seem to be of games where information needs to stay private, on the back-end. In-game, voting sessions can begin, the players’ votes are only known to the worker, who tallies them, then sends the front-end the result. The worker randomly gives roles to the players, most of which are unknown to other players, but known to the worker.
So Channels can be used to make a website with multiple websocket chat rooms, but now that I have turned the chat room into a game room, idk where to store game state besides the worker. Are you suggesting the one worker could hold the game state of all running games?
Those were examples, because I’m not sure you’d be familiar with the actual titles of the games being played - all of which do have information that must remain private. (Actually, “Rock-Paper-Scissors” does meet that criteria. A player must not be aware of the selection made by their opponent until after their own selection is made.) Regardless, that’s not a relevent issue here.
The worker doesn’t “hold” the state. The game states are stored in the database. When the worker receives a message, it retrieves the current state from the database, updates it, and sends out updates as appropriate. There are no design limits to the number of concurrent games that can be handled by a worker.
Are the workers the means by which you’re writing game state into the database? As I have it now, game state is in redis memory, just variables tracked by the worker, not database.
Yes.
That’s not significantly different - you could manage it in a similar manner. You would just need to manage the indexing yourself. (You could have something like a “game_id” as index for all the active games, with each entry being the redis key(s) for the data needed for that instance of the game.)
And you’re not seeing game or code errors causing any of your workers to stop?
The system has been up for more than two years now and have never experienced a failure.