🎓 A1Learner
🔍
0 of 46 lessons completed

Elixir Applications and Children

An application is a started program whose root is a supervisor built from a list of children. Starting the application starts that supervisor, and the supervisor starts every child in the list.

Starting the application starts its children

The start function builds the root supervisor from two children. Both workers answer.

defmodule Worker do
  use GenServer
  def start_link({name, initial}), do: GenServer.start_link(__MODULE__, initial, name: name)
  def init(initial), do: {:ok, initial}
  def handle_call(:get, _from, state), do: {:reply, state, state}
  def handle_cast(:inc, state), do: {:noreply, state + 1}
end
defmodule CounterApp.Application do
  use Application
  def start(_type, _args) do
    children = [
      %{id: :a, start: {Worker, :start_link, [{:a, 10}]}},
      %{id: :b, start: {Worker, :start_link, [{:b, 20}]}}
    ]
    Supervisor.start_link(children, strategy: :one_for_one)
  end
end
{:ok, sup} = CounterApp.Application.start(:normal, [])
IO.inspect(GenServer.call(:a, :get))
IO.inspect(GenServer.call(:b, :get))
Supervisor.stop(sup)

The root supervisor restarts a failed child

Both children are raised by one. Then child a fails, and only a starts again from 10.

defmodule Worker do
  use GenServer
  def start_link({name, initial}), do: GenServer.start_link(__MODULE__, initial, name: name)
  def init(initial), do: {:ok, initial}
  def handle_call(:get, _from, state), do: {:reply, state, state}
  def handle_cast(:inc, state), do: {:noreply, state + 1}
end
defmodule CounterApp.Application do
  use Application
  def start(_type, _args) do
    children = [
      %{id: :a, start: {Worker, :start_link, [{:a, 10}]}},
      %{id: :b, start: {Worker, :start_link, [{:b, 20}]}}
    ]
    Supervisor.start_link(children, strategy: :one_for_one)
  end
end
{:ok, sup} = CounterApp.Application.start(:normal, [])
GenServer.cast(:a, :inc)
GenServer.cast(:b, :inc)
IO.inspect(GenServer.call(:a, :get))
IO.inspect(GenServer.call(:b, :get))
Process.exit(GenServer.whereis(:a), :kill)
Process.sleep(100)
Supervisor.which_children(sup)
IO.inspect(GenServer.call(:a, :get))
IO.inspect(GenServer.call(:b, :get))
Supervisor.stop(sup)

Stopping the root ends the application workers

The root supervisor is stopped at the end of this block. Both workers are gone with it.

defmodule Worker do
  use GenServer
  def start_link({name, initial}), do: GenServer.start_link(__MODULE__, initial, name: name)
  def init(initial), do: {:ok, initial}
  def handle_call(:get, _from, state), do: {:reply, state, state}
  def handle_cast(:inc, state), do: {:noreply, state + 1}
end
defmodule CounterApp.Application do
  use Application
  def start(_type, _args) do
    children = [
      %{id: :a, start: {Worker, :start_link, [{:a, 10}]}},
      %{id: :b, start: {Worker, :start_link, [{:b, 20}]}}
    ]
    Supervisor.start_link(children, strategy: :one_for_one)
  end
end
{:ok, sup} = CounterApp.Application.start(:normal, [])
Supervisor.stop(sup)
IO.inspect(GenServer.whereis(:a) == nil)
IO.inspect(GenServer.whereis(:b) == nil)

Example

defmodule Worker do
  use GenServer
  def start_link({name, initial}), do: GenServer.start_link(__MODULE__, initial, name: name)
  def init(initial), do: {:ok, initial}
  def handle_call(:get, _from, state), do: {:reply, state, state}
  def handle_cast(:inc, state), do: {:noreply, state + 1}
end
defmodule CounterApp.Application do
  use Application
  def start(_type, _args) do
    children = [
      %{id: :a, start: {Worker, :start_link, [{:a, 10}]}},
      %{id: :b, start: {Worker, :start_link, [{:b, 20}]}}
    ]
    Supervisor.start_link(children, strategy: :one_for_one)
  end
end
{:ok, sup} = CounterApp.Application.start(:normal, [])
GenServer.cast(:a, :inc)
GenServer.cast(:b, :inc)
IO.inspect(GenServer.call(:a, :get))
IO.inspect(GenServer.call(:b, :get))
Process.exit(GenServer.whereis(:b), :kill)
Process.sleep(100)
Supervisor.which_children(sup)
IO.inspect(GenServer.call(:a, :get))
IO.inspect(GenServer.call(:b, :get))
Supervisor.stop(sup)

Key points

  • Application: a program unit that boots through one start function.
  • start: the function that returns the root supervisor for the application.
  • Children list: the list of child specifications handed to the root supervisor.
  • Root supervisor: the supervisor at the top of the application, started directly by start.
  • Direct call: in a script the start function is called directly with the arguments normal and an empty list.

In this example, starting the application returns its root supervisor, and both children answer after being raised to 11 and 21. When child b fails, the root supervisor restarts only b. After the failure, a still answers 11 and b answers 20 again. The root supervisor is stopped at the end.

Note

the application module uses the Application behaviour, so its start function has the shape the runtime expects.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

What does an application start function return?