thiagomajesk

thiagomajesk

Difference between Supervisors and DynamicSupervisors what am I missing?

Hi! I’ve been diving deeper into Elixir recently and reading through some of the guides and docs about Processes and Supervisors. After reading Dynamic supervisors - The Elixir programming language and comparing the docs from Supervisor — Elixir v1.13.4 and DynamicSupervisor — Elixir v1.13.4 I’m not sure I fully grasped the advantages of DynamicSupervisors.

I think the confusion is mainly because I’ve seen that both modules have the same function to start a child “dynamically”: Supervisor.start_child/2 and DynamicSupervisor.start_child/2. However, every guide I read, states that DynamicSupervisors’s main purpose is to add children to the supervision tree dynamically. What am I missing here?

There’s an example in this code base that shows a Supervisor adding children dynamically as well, so I’m not sure I understand the advantages of one over the other.

PS.: Not directly related to the topic, but I also notice that Supervisor.child_spec/2 and DynamicSupervisor.child_spec/1 have some different semantics that seems not documented. The latter doesn’t allow us to pass the module and uses the name option to define the spec id.

Most Liked

josevalim

josevalim

Creator of Elixir

I improved the docs to say:

The Supervisor module was designed to handle mostly static children
that are started in the given order when the supervisor starts. A
DynamicSupervisor starts with no children. Instead, children are
started on demand via start_child/2 and there is no ordering between
children. This allows the DynamicSupervisor to hold millions of
children by using efficient data structures and to execute certain
options, such as shutting down, concurrently.

17
Post #4
dimitarvp

dimitarvp

Permanent == started on app startup and staying there until the app shuts down.

Thanks to this distinction, DynamicSupervisor allows you to start and stop children processes at any time. You also are not strictly mandated to stop them; they will be stopped when the supervisor itself is stopped (although it’s definitely a good idea to stop children proactively after they’ve done their job IMO).

To me, using DynamicSupervisor is appropriate in two scenarios:

  1. When you would like to spawn quite a lot of (say, at least 200,000+) processes because I’d wager then a performance (or memory) impact would start becoming noticeable.
  2. When you need to create processes in response to – or because of the specifics of – external systems whose resources you have to monitor e.g. a web crawling service to which you give a new domain to crawl. It would need to spawn processes to enumerate URLs and then maintain a small pool of workers to do the crawling (and apply rate limits if applicable).

I’d say especially the latter option is pretty valid; there are many real-world examples where you cannot neatly plan a supervision from the start because things do change at runtime. DynamicSupervisor is ideal for this.

derek-zhou

derek-zhou

I think the DynamicSupervisor is only a special case of Supervisor that handle only dynamic children. In Erlang there is only supervisor. It is a good habit to separate the static children and the dynamic children in different branches of the supervision tree.

msimonborg

msimonborg

The way that codebase is using Supervisor.start_child/2

  def init(_args) do
    children = [
      World.Location
    ]

    Supervisor.init(children, strategy: :simple_one_for_one)
  end

  def start_child(opts) do
    Supervisor.start_child(__MODULE__, [opts])
  end

is deprecated

  def start_child(supervisor, args) when is_list(args) do
    IO.warn_once(
      {__MODULE__, :start_child},
      "Supervisor.start_child/2 with a list of args is deprecated, please use DynamicSupervisor instead",
      _stacktrace_drop_levels = 2
    )

    call(supervisor, {:start_child, args})
  end

  # in def init/2
        :simple_one_for_one ->
          IO.warn(
            ":simple_one_for_one strategy is deprecated, please use DynamicSupervisor instead"
          )

Migrating from Supervisor’s :simple_one_for_one

I think if you have a supervisor with “regular” strategy, e.g. :one_for_one, and start processes with Supervisor.start_child/2 it’s assumed they’ll be permanent. DynamicSupervisor should be used for dynamic start/termination of arbitrary children.

Supervisor.child_spec/2 is a unique function which receives any child spec (Module, {Module, arg}, or map) and a list of overrides, and returns that child spec with the overrides applied. DynamicSupervisor.child_spec/1 returns a child spec to start a DynamicSupervisor under a supervisor, the same way Registry.child_spec/1 returns a child spec to start a Registry under a supervisor.

iex> DynamicSupervisor.child_spec(name: MyApp.DynamicSupervisor)
%{
  id: MyApp.DynamicSupervisor,
  start: {DynamicSupervisor, :start_link, [[name: MyApp.DynamicSupervisor]]},
  type: :supervisor
}
iex> |> Supervisor.child_spec(id: OverriddenID, shutdown: 10_000)
%{
  id: OverriddenID,
  shutdown: 10000,
  start: {DynamicSupervisor, :start_link, [[name: MyApp.DynamicSupervisor]]},
  type: :supervisor
}
msimonborg

msimonborg

IMO the documentation seems clear about it, but I could see how it would be confusing that they’re both supervisors and DyanmicSupervisor says “see Supervisor”, but FWIW it does not say “see Supervisor.child_spec/2”. I think it’s pointing to the Supervisor docs in general for more info about child specs. Maybe it could link directly to the child_spec/1 section. Returns a specification to start a dynamic supervisor under a supervisor is very different from what’s written in the Supervisor.child_spec/2 doc. The doc for DynamicSupervisor.child_spec/1 is much more similar to Registry.child_spec/1 or Agent.child_spec/1.

I’ll admit this is maybe a bad or incomplete assumption but gleaned from what I’ve seen written elsewhere on the forum. I think José’s new documentation makes it more clear that DynamicSupervisor is preferred for efficiency of starting and stopping thousands or millions of processes, because there is no specific ordering of them. My takeaway which may be incorrect is that when you add a child spec to a Supervisor it will always be added to the end of the child list and never removed, and shutdown order is always strictly preserved.

Where Next?

Popular in Questions Top

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
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
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
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
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
yurko
Here are few pieces of (common) Linux knowledge that we use for reasonably small one server apps. We use Ubuntu but this should work for ...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
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
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 42633 214
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement