ashton314

ashton314

What can go wrong with GenServers?

Howdy! I’m a researcher trying to understand better how people use Elixir. I have a fair amount of personal experience with Elixir, but I need more than one data point. :slight_smile: I’m particularly interested in GenServers—particularly how they can go wrong.

Have you ever encountered a GenServer that was sensitive to the order of certain messages? E.g. imagine you had a GenServer acting as a proxy for a web service; you might need to send the server :connect to get a token, and only after that could you send it {:request, body} messages.

When have you had bugs with GenServers?

Most Liked

al2o3cr

al2o3cr

As @derek-zhou points out, message-ordering isn’t generally much of a problem. However, the code you described sounds like it has a different issue that’s more common: using one process when you really want a supervision tree.

Instead of a single “proxy” that tracks all the connections made through it, a “BEAMier” approach would make the initial connect spawn a new process focused solely on that connection.

On the flip-side of “too much state in one process” is “no state in the process”, the dreaded “using GenServers for code organization”. I’ll leave further discussion to the docs.

A gotcha that’s easy to miss until it becomes a headache in production: the restart threshold max_restarts in supervisors needs to be tuned once there are many children. Very frustrating to have 3 crashes in 5s bounce your DynamicSupervisor with 3k children :crying_cat_face:

When that supervisor restarts (or on a cold system boot), you can also run into another scaling problem: the “thundering herd”, where those 3k children start up and ALL try to make a SQL query in the same 10ms. Combine those DB timeouts with a low max_restarts on the supervisor and you are now officially Having A Bad Time.

rvirding

rvirding

Creator of Erlang

As you have already mentioned there are no real guarantees in which order the messages sent from different processes will arrive. If this is really important to you then you will have to synchronise the sending processes in some way.

One thing which is guaranteed is that the GenServer process handles the messages in the order in which they arrive and it only handles one message at a time. So for example when it gets a call messages it will call the handle_call callback and the GenServer toploop won’t handle any messages in anyway until the handle_call returns.

Note however if you in one of callbacks communicates with other processes, this is very very very common, then as there is only one message queue per process (NO there is no way around this) then your messages might become interspersed with more requests coming into the GenServer. It is upto to you make sure your message tagging ensures that you don’t receive any GenServer requests cause then they are gone. Also remember that any messages you leave in the message queue will be picked up by the GenServer toploop and most likely be processed in a handle_info callback.

Remember the BEAM/Erlang/Elixir process semantics is very simple and straight forward, e.g one message queue where everything gets entered in order and there are no interrupts. Its very the KICASS principle. :wink: :laughing:

D4no0

D4no0

One of the dangerous things that can go wrong with genserver is leaking memory when using large binaries. Depending on your orchestration, you can easily take the server down too if you run out of memory.

There are lot of articles on this topic, here is one of them: https://medium.com/coletiv-stories/genservers-memory-issues-ef42cc42e3e9

Last Post!

dimitarvp

dimitarvp

You can read about it here, it’s IMO well-explained: Elixir, A Little Beyond The Basics - Part 8: genservers

One very important excerpt about the process messages:

# send
:hello

 # cast
{:"$gen_cast", :hello}

# call
{ :"$gen_call",
  {#PID<0.110.0>, [:alias | #Reference<0.426212949.4092919813.244647>]},
  :hello
}

GenServer.cast and GenServer.call basically do send messages with an opinionated format. There’s no magic, just stuff that’s handled for you so you have an easier time – that’s all really.

But if you want to start peeking under the hood you have to make sure you either don’t match on these special messages or you do get them but also forward them further, otherwise GenServer.cast and GenServer.call will not work.

Where Next?

Popular in Questions Top

RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
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
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

Other popular topics Top

jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49084 226
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement