Adworse Codes Here

Rubyist Elixir Journey

Menu
  • About me
  • Privacy Policy
Menu

Singleton GenServer: Short track to the orphanage

Posted on July 16, 2022July 18, 2022 by Dima Ermilov

While writing a GenServer as a singleton on a multi-node system, it’s easy to come up with something like this:

def start_link(_number, _opts \\ []) do
  case GenServer.start_link(__MODULE__, :ok, name: {:global, __MODULE__}) do
    {:ok, pid} ->
      {:ok, pid}

    {:error, {:already_started, pid}} ->
      {:ok, pid}
  end
end

It works perfectly until it doesn’t: when our singleton process goes down, the only supervision tree aware of this would be the one that started it. Every other node won’t get any message, so while the process is restarting, the caller will fail with Process is not alive. Even worse: if for some reason you are using the PID that is returned from start_link/2 in your code, your code on other nodes will never know the PID changed after the restart.

Luckily, it seems to be easily fixable with Process.link/1:

def start_link(_number, _opts \\ []) do
  case GenServer.start_link(__MODULE__, :ok, name: {:global, __MODULE__}) do
    {:ok, pid} ->
      {:ok, pid}

    {:error, {:already_started, pid}} ->
      # Now the process will send DOWN message to supervisors on every single node
      Process.link(pid)
      {:ok, pid}
  end
end

Related

Category: Learned the Hard Way

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • The Curious Case of String.slice/3
  • Singleton GenServer: Short track to the orphanage

Recent Comments

No comments to show.

Archives

  • July 2022

Categories

  • Learned the Hard Way
  • We Need To Go Deeper
©2023 Adworse Codes Here