deerob4
What is the right way to communicate between two GenServers?
I’m creating a game system, which includes a lobby and a countdown timer. Once enough players have joined, the countdown timer begins and upon completion tells the lobby to start the game.
Both are implemented as separate GenServers, registered using a via tuple in Registry. I’m a bit unsure of the best way for CountdownTimer to notify Lobby that the countdown has completed. I can think of a few different options:
-
Use
Registry.lookup/2to get the pid of theLobbyprocess, thensendfrom the countdown timer to be handled inhandle_info. -
Add a
countdown_completed/1function to the lobby that takes the lobby id and callsGenServer.cast/2to do whatever it needs.CountdownTimercan then call this upon completion. I’m not a fan of this because it seems to tie the two together a bit much. -
Implement a pubsub mechanism using either
RegistryorPhoenix.PubSubso that the lobby can subscribe to the countdown completion event. This also has the advantage that my Phoenix channel could subscribe as well. This seems to be the most flexible solution, but I worry that it might be overkill.
I’d appreciate some advice on which method (or an alternative one) to go for. Thank you!
Most Liked
LostKobrakai
Imho processes should be separated based on their runtime behaviour (error separation and stuff like that) and not on “concerns” like you’d separate classes by. The lobby and the timer are entangled in their runtime behavior so in my opinion there’s no reason to not run them in the same process.
LostKobrakai
I’m wondering why you need two processes here in the first place. Couldn’t the lobby do it’s own countdown.
peerreynders
This is a valid question. The scope of the problem you have described could be solved with the Lobby process using Process.send_after/4 and simply process the “complete” msg value when it is returned via the handle_info/2 callback.
I’m not a fan of this because it seems to tie the two together a bit much.
Now lets say there is a good reason for the CountdownTimer process to exist - maybe because it somehow coordinates a UI display of the countdown timer.
You can take inspiration from send_after. So rather than defining Lobby.countdown_completed/0, you solve the problem in the CountdownTimer API when the countdown is initiated.
CountdownTimer.new_timer(completed_msg, time)
CountdownTimer will implement this as a call so it will get from for free.
- it can either use
send_afteritself with a{from, completed_msg}message value - or store
{from, completed_msg}in the process state for later
So when the time comes CountdownTimer simply uses GenServer.cast(from, completed_msg) to return the requested completed_msg value to the Lobby that requested the timer (which it then has to handle in its own handle_cast/2).
In this particular situation I think it’s fine as the CountdownTimer process really doesn’t care if the Lobby process has died. Furthermore the CountdownTimer could just slap a monitor onto each of its client processes so that it can cleanup their timers as soon as possible.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance










