mariosangiorgio

mariosangiorgio

Is giving a GenServer `__MODULE__` as name a good practice?

Hello, I was reading the Elixir School page on GenServer and I see that in the examples they use __MODULE__ as the name. For instance:

defmodule SimpleQueue do
  use GenServer
  ...
  def start_link(state \\ []) do
    GenServer.start_link(__MODULE__, state, name: __MODULE__)
  end

  def queue, do: GenServer.call(__MODULE__, :queue)
  ...
end

I think I understand what it does, it looks to me that it’s effectively creating a singleton GenServer, but coming from the object oriented world I’m a bit reluctant in adding singletons to my codebase.

I was wondering if this is considered a good practice in the Elxir world or if there is any other recommended pattern.

I’m aware that the answer to this question is probably “it depends on what you’re trying to do” but I’m trying to understand if, in general, having GenServers with __MODULE__ as their name is considered to be good or not.

Most Liked

sasajuric

sasajuric

Author of Elixir In Action

I believe there are two questions embedded here.

  1. Should a GenServer be registered under a local name?
  2. If yes, is __MODULE__ a good choice?

I’ll answer the 2nd one first, because it’s easier. You could, in theory pick any arbitrary atom for the name, but I believe that a module atom is a good choice which ensures that the registered name is unique, since you can’t have two different modules bearing the same name. Personally, I use __MODULE__ as the name option very frequently.

The first question is a bit more complex. I also came to Elixir (well, Erlang) with a lot of OO background, and I had the same doubts myself. In fact, in my early work, I avoided registered names as much as I could.

Similar to you, I also consider locally registered processes as (local) singletons. However, while singletons are mostly bad in OO, registered processes are more frequently used in Erlang/Elixir. The reason is that GenServers (sometimes called actors) are more similar to services, then they are to objects.

A GenServer (or any other kind of process) is more like a separate program, and therefore it can be regarded as a small service in the system. Just like with modern microservices, the communication between different processes is based on messaging. In order to send a message, a client service needs the address of the target (server) service. In the case of processes, that address is a pid.

However, keep in mind that processes might get restarted, and a restarted process gets a different pid. If the client is keeping a pid of the server process, it might end up with a stale pid, and it can’t talk to the server process anymore. A named registration helps you there, because clients don’t care about the exact address, they use the symbolic name to communicate with the server process. It’s kind of like a domain name, with pids being more like IP addresses.

Of course, this has its downsides too. In your example, you can have at most one queue per BEAM instance, which can seem quite restrictive. If you want to run more instances, then you can use Registry, which allows you to have arbitrary term as the name. Then, you can give names such as {__MODULE__, 1}, {__MODULE__, 2}, … to different queue instances.

Either way, the name corresponds to the role the process has in the system. The name SimpleQueue means that the process is the queue (the one and only in the BEAM instance). The name {SimpleQueue, 1} would represent a queue with the ID 1. With such naming, you can have more queues in the system, but there can be at most one per each ID.

Going beyond, you can also give so called global names, which have scope in the entire cluster.

Finally, we don’t always register our processes. For example, I sometimes rely on plain pids if the client and the server are tightly coupled to the point that one can’t exist without the other.

I’ve elaborated some more on the topic in this talk. It’s somewhat outdated, because since then we’ve got Registry in Elixir (so my examples with :gproc are not so relevant), but the ideas are still pretty much the same.

24
Post #3
michalmuskala

michalmuskala

One thing to additionally consider is testing. We’re spoiled in Elixir by the concurrency, so whenever I’m writing systems, I’m thinking how can I test them concurrently. This usually also turns out to be helpful when later scaling the system, but that’s another story.

Even, if I ultimately will run the process registered under a local name, I will rarely register the name directly in start_link - instead I will accept an argument with a name. This can be later used to pass the name from the supervisor to create a named actor for the production system and integration testing. At the same time, this allows easily spawning additional processes in tests for unit testing the particular process. This is a bit more verbose, because it requires passing in the process name/pid as an additional argument to the functions, but this isn’t that big price to be paid and can be worked around as well (the simplest solution being a default argument).

10
Post #4
sorentwo

sorentwo

Oban Core Team

I aim for testability in much the same way. Between a default options argument and Keword.put_new/3 with the module as the fallback name you get the best of both worlds.

NobbZ

NobbZ

This is totally fine, as long as you are sure there will be not more than one of these GenServer at a time. Often this holds and just using the modules name is one of the easiest things to do for the system and the developer. It’s easy recognizable and to remember.

Perhaps other people having actually a keyboard at their hand instead of a mobile phone might give more in depth explanations.

mariosangiorgio

mariosangiorgio

Thank you all for your answers, they helped me a lot in understanding how I everything works in Elixir and how I should structure my applications.

I wasn’t thinking at GenServers (or processes in general) as services and the issues pids have when they get restarted. From that perspective everything makes sense.

Where Next?

Popular in Questions Top

JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
dokuzbir
Hello, I am trying to convert my lists to string without losing brackets.For start i have 3 map. They look like these buyer = %{ id: ...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
Fl4m3Ph03n1x
Background Let’s assume I have a typical GenServer that receives messages as requests, does some operation in a DB and returns responses....
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement