Using GenServer :via

Posted on 11 Aug 2017 by Eric Oestrich

For a side project I wanted to figure out how to use :via with GenServer. I have two different GenServers that should respond to similar GenServer interface, NPCs and User Sessions.

I went this route because I already had two registries going, one for each type of instance. The NPCs registry was a standard unique registry and the session registry was a duplicate registry so I could easily determine which sessions were online and had a connected user.

With that in place it was very easy to get a :via module set up. I did not have to handle two of the required functions for :via which deal with registering and unregistering.

:via whereis_name

The first thing I had to get going was finding the correct PID given an existing registry. For NPCs I simply delegated off to the elixir registry since it was already built in. I patterned matched against a tuple to determine the split.

def whereis_name({:npc, id}) do
  Registry.whereis_name({Game.NPC.Registry, id})
end
def whereis_name({:user, id}) do
  player = Session.Registry.connected_players
  |> Enum.find(&(elem(&1, 1).id == id))

  case player do
    {pid, _} -> pid
    _ -> :undefined
  end
end

:via send

This was a similar instance, delegate off to the standard registry for NPCs and find the pid for user sessions.

def send({:npc, id}, message) do
  Registry.send({Game.NPC.Registry, id}, message)
end
def send({:user, id}, message) do
  case whereis_name({:user, id}) do
    :undefined ->
      {:badarg, { {:user, id}, message} }
    pid ->
      Kernel.send(pid, message)
      pid
  end
end

Conclusion

It was fairly easy to get this going and now I can send a message to either set of GenServers by only know their database ids. I can start to hide the knowledge of if the server is a session or an NPC pid going forward for things that won’t care.

comments powered by Disqus
Creative Commons License
This site's content is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License unless otherwise specified. Code on this site is licensed under the MIT License unless otherwise specified.