ream88

ream88

Understanding process links

Hello,

I have an Elixir app where a process depends on another process to be alive and send messages back. This second process is mainly a database connection and may occasionally fail. I created an example app below, which mimics the structure. ModuleA my worker process, ModuleB is the database connection:

defmodule Test.ModuleA do
  use GenServer

  def start_link(opts \\ []) do
    name = Keyword.get(opts, :name, __MODULE__)
    GenServer.start_link(__MODULE__, nil, name: name)
  end

  def init(_) do
    IO.puts("#{__MODULE__} starting")

    {:ok, nil}
  end
end

defmodule Test.ModuleB do
  use GenServer

  def start_link(opts \\ []) do
    name = Keyword.get(opts, :name, __MODULE__)
    GenServer.start_link(__MODULE__, nil, name: name)
  end

  def init(_) do
    IO.puts("#{__MODULE__} starting")

    Process.send_after(self(), :crash, 5000)

    {:ok, nil}
  end

  def handle_info(:crash, _state) do
    raise "boom"
  end
end

Using the application’s main supervisor like this everything works as expected, both processes are restarted when the DB connection (ModuleB) crashes:

def start(_type, _args) do
  children = [
    # Starts a worker by calling: Test.Worker.start_link(arg)
    # {Test.Worker, arg}

    Test.ModuleB,
    Test.ModuleA
  ]

  # See https://hexdocs.pm/elixir/Supervisor.html
  # for other strategies and supported options
  opts = [strategy: :rest_for_one, name: Test.Supervisor]
  Supervisor.start_link(children, opts)
end

asciicast

But because the ModuleB is not really part of my application but of an external package we use, I don’t really can supervise it in my supervisor. Therefore my idea was to link ModuleA to ModuleB like so (and also changed my supervisors strategy back to :one_for_one):

defmodule Test.ModuleA do
  use GenServer

  def start_link(opts \\ []) do
    name = Keyword.get(opts, :name, __MODULE__)
    GenServer.start_link(__MODULE__, nil, name: name)
  end

  def init(_) do
    IO.puts("#{__MODULE__} starting")

    Test.ModuleB
    |> Process.whereis()
    |> Process.link()

    {:ok, nil}
  end
end

However this results in a very weird problem where my app completely crashes after two simulated connection problems:

asciicast

What’s going on? Did I misunderstood process links and/or supervisor config?

Marked As Solved

LostKobrakai

LostKobrakai

So the supervisor you start in your application.ex uses the default of max 3 restarts within 5 seconds, before itself crashes. You’re doing 4 restarts per 5 seconds (restart A and B, wait 5 seconds and again restarting A and B). For :rest_for_one only the crashing ModuleB counts against that limit, not all the other processes restarted by the supervisor as a result of that crash.

Also unexpectedly to many people the root process of an application (the one you return the pid from c:Application.start/2) will never be restarted. It’s not a child of a supervisor and the application will stop as soon as the root pid crashes/stops.

Last Post!

LostKobrakai

LostKobrakai

:rest_for_one would hardly ever survive a single crash if it would count the restarts of the “rest”. For one_for_one both processes count, as A is restarted because it stopped, not because the supervisor stopped it.

Where Next?

Popular in Questions Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 130579 1222
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 54092 488
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31525 112
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 49134 226
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New

We're in Beta

About us Mission Statement