Welcome @emuminov !
There are a couple different ways to handle this.
Personally, I’m a fan of using multiple processes.
I do this type of thing in my board game engine in that my games implement a time limit for most actions.
I rely heavily upon Channels Worker processes, all communicating through the channels layer.
Each game title manages all the instances of a game. (For example, if I had chess as a game, there would be one Worker running all the chess games being played.
The workers are all single-threaded synchronous code such that received messages are processed in the strict order in which they are received, and are processed to completion before the processing of the next message is started.
In addition to those workers, there’s a separate Timer Worker that, when given a game instance, message, and a duration, sends that message back to the Game Worker requesting it at the expiration of the duration. (The Game Worker can also send a Cancel message to the Timer Worker to cancel a particular timer.)
From the perspective of the Game Worker, then the Timer Worker message works much in the same manner as any other channel messages being sent to it by a consumer - it’s an indication that the Game needs to somehow change its state and send appropriate messages back out to the consumers.
In my case, when a game enters a state where a person has a limited amount of time to make a choice, the Game Worker sends the update to the player, then sends the message to the Timer Worker to start a timer.
If the player responds before the timer message is received, then everything’s good. If the timer message is received before the player has acted, then the game takes the predetermined action based upon the game state.
In your case, you could change the concept slightly such that the Timer Worker could be programmed to send a message at periodic intervals (e.g. 33 ms) to the Game Worker. The Game Worker then uses that input to change the state.
Side note: While testing, you can use a single instance of runworker
command to run all the workers within a single Daphne instance. However, in a deployment environment, I run a separate Daphne instance for each Worker in addition to the Daphne instance handling the consumers. This is to ensure that no individual game can interfere with the processing of the timer or other game title.