Hi there,
I’m working on a bot to do social games on the fedi, and using the mastodon-async crate for communicating with the ActivityPub server in question. At the moment I’m using tokio mt as a runtime, though I’m new at async so if you think I shouldn’t let me know.
The pattern I want to implement is the following:
- At any given time, a user sends a “play” message to the bot.
- If the player list is empty, the player is added to it awaiting someone else.
- Otherwise, the bot checks if there are enough players on its list (who have previously sent a play message). For some games, enough is 1, since it’s a 2-player game, for some it’s 3 or more.
- If there are enough players, play commences. list is cloned for that match, then emptied so other players can get in.
What I’m not very clear is how to keep this list to assure that sequence will be respected. I.a., if two play messages come reasonably quick together, I want one to be processed, then entered on the list, or get the match to start; then the other to get processed.
My current thoughts:
- I could use a channel that receives the player accounts. When a new player is added, it performs the logic.
- I could use a mutex with a list (or an option player value for the degenerate case of 2-player games).
Any thoughts on what the reasonable thing to do is here? I’m very new to async and while I realise there’s probably lots of ways to do this, they’re not all equally ergonomic and I want to avoid myself future pain.
Both would work. The channel-based one is probably more ergonomic, because there you can write the sequence linearly just as you described.
One important thing for both approaches is that you must not use blocking variants of the mutex or channel. There are async versions of both available, though.
So probably the tokio mpsc channel, right? Why is it not possible tu use normal sync channels? I’ve read about it but I don’t understand the reason.
Also I’m thinking of spawning a thread to do this part, or should it run on the tokio main function?
tokio uses thread pools for scheduling async tasks, which generally is what you want (because spawning threads is expensive and can lead to DoS vulnerabilities).
If you block in an async task, the thread the task is running on is no longer available to other async tasks. If you have the same amount of tasks currently blocking as you have threads, the whole system grinds to a halt.