GenServer, DynamicSupervisor and Registry: The Elixir Triad To Manage Processes

helvantine
Level Up Coding
Published in
3 min readDec 15, 2020

--

Originally on Wallpaper Flare

Over the previous year, my programmer’s journey has brought me to the realm of Elixir, a functional programming language that compiles to the Erlang VM. While Elixir offers syntactical joys like pattern matching and the pipe operator, it is often highlighted as ideal for highly concurrent and fault-tolerant applications.

What this means in practice eluded me for some time, until I understood how three native modules — GenServer, DynamicSupervisor and Registry — can work together.

Imagine the scenario of a multiplayer game. In building it, you may need:

  • The ability to run a large, dynamic number of games concurrently.
  • The ability to look up a running game — for example, so that players can join it.
  • The ability to automatically restart a game process if it crashes for any reason.

While the above logic is well within the realm of software development, programming it may represent significant overhead with no product value. With Elixir, however, you can solve this problem by using three core modules:

GenServer. This abstracts the implementation of concurrent processes, and comes with a standard interface to manage state and execute logic. Each game instance would correspond to a GenServer process.

DynamicSupervisor. This manages the arbitrary and evolving number of games, starting them as child processes on demand and restarting them if they crash.

Registry. This provides a key-value store for processes, allowing us to look up a running game easily.

And — surprisingly — you can do this in just a few lines of code.

First, you need a Supervisor monitoring the DynamicSupervisor and the Registry. You can think of this as the application entrypoint, with two child processes responsible for individual games.

Then, the DynamicSupervisor. The start_child/1 method will start a new game with a custom name set by the given argument.

And, last but not least, a GenServer defining game instances.

The key element here is the via_tuple/1 method used in start_link/1, the call that starts the GenServer process. The :via option allows us to map the processes to a custom name in the Registry, which can then be re-used to interact with the given process.

Read more in the documentation.

You can now visualise how this works in the interactive shell.

Create handy aliases and start the Supervisor. This also launches Registry and GameSupervisor as child processes.
Start separate game processes and look them up in the Registry using the given name.
Interact with the games separately using the given name — in this case, adding players. Check the game state.
Crash one game with a reason that is not :normal and see that it has been restarted with a new process ID (#PID) but the same name.

And this is it. Do you know other good ways to manage concurrent processes? I am all ears.

Happy coding 🚀

Special thanks to my colleagues at OMG Network for the Elixir journey.

--

--