Fun With Elixir OTP by Daniel Jaouen

2017-11-18

Today we’re going to be studying Elixir’s OTP facilities. First, key this in as lib/supervisor_test/server.ex:

defmodule SupervisorTest.Server do
  use GenServer

  def start_link(pid) do
    GenServer.start_link(__MODULE__, [pid])
  end

  def get_pid(pid) do
    GenServer.call(pid, :get_pid)
  end

  def init([pid]) do
    {:ok, pid}
  end

  def handle_call(:get_pid, _from, pid) do
    {:reply, pid, pid}
  end

  def handle_call(message, from, pid) do
    IO.inspect(from)
    {:reply, pid, pid}
  end

  def handle_info(:stop, pid) do
    {:stop, "GenServer stopped", pid}
  end
end

First, we notice we have the standard API call to GenServer.start_link. This function implicitly calls init. Then we have an API call (get_pid) that runs a GenServer.call(pid, :get_pid). The rest of the file is pretty straightforward.

Then, key this in as lib/supervisor_test/supervisor.ex:

defmodule SupervisorTest.Supervisor do
  use Supervisor

  def start_link do
    Supervisor.start_link(__MODULE__, [4, 5, 6, 7])
  end

  def init(args) do
    IO.inspect(args)
    worker_opts = [restart: :permanent]
    workers = [
      worker(SupervisorTest.Server, [self()], worker_opts),
    ]
    opts = [strategy: :simple_one_for_one,
            max_restarts: 5,
            max_seconds: 5]
    supervise(workers, opts)
  end
end

First, we have an API call to Supervisor.start_link with args [4, 5, 6, 7]. This function implicitly calls init. We then IO.inspect args and then start the supervision tree. Notice that we’re using a :simple_one_for_one server here, meaning the child will need to be started manually.

Now, key this in as lib/supervisor_test.ex:

defmodule SupervisorTest do
  use Application

  def start(type, args) do
    IO.inspect(type)
    IO.inspect(args)
    SupervisorTest.Supervisor.start_link
  end
end

We see here that we’re first examining the type and args args in start. We then make our API call to SupervisorTest.Supervisor.start_link.

Now key this in as mix.exs:

defmodule SupervisorTest.Mixfile do
  use Mix.Project

  def project do
    [
      app: :supervisor_test,
      version: "0.1.0",
      elixir: "~> 1.5",
      start_permanent: Mix.env == :prod,
      deps: deps()
    ]
  end

  # Run "mix help compile.app" to learn about applications.
  def application do
    [
      extra_applications: [:logger],
      mod: {SupervisorTest, [1, 2, 3, 4]}
    ]
  end

  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
    ]
  end
end

We see here that we’re starting SupervisorTest with the arguments [1, 2, 3, 4].

Run up an iex -S mix session and key these commands in:

○ iex -S mix
Erlang/OTP 20 [erts-9.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]

:normal
[1, 2, 3, 4]
[4, 5, 6, 7]
Interactive Elixir (1.5.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {:ok, supervisor} = SupervisorTest.Supervisor.start_link
[4, 5, 6, 7]
{:ok, #PID<0.115.0>}
iex(2)> Supervisor.which_children(supervisor)
[]
iex(3)> {:ok, server} = Supervisor.start_child(supervisor, [])
{:ok, #PID<0.118.0>}
iex(4)> SupervisorTest.Server.get_pid(server)
#PID<0.115.0>
iex(5)> send server, :stop
:stop
iex(6)>
08:39:29.525 [error] GenServer #PID<0.118.0> terminating
** (stop) "GenServer stopped"
Last message: :stop
State: #PID<0.115.0>
Supervisor.which_children(supervisor)
[{:undefined, #PID<0.121.0>, :worker, [SupervisorTest.Server]}]
iex(7)> server = supervisor |> Supervisor.which_children |> Enum.at(0) |> elem(1)
#PID<0.121.0>
iex(8)> SupervisorTest.Server.get_pid(server)
#PID<0.115.0>
iex(9)>

We see that immediately :normal, [1, 2, 3, 4] and [4, 5, 6, 7] are printed out. This is expected because we IO.inspect type and args in SupervisorTest.start and then IO.inspect args in SupervisorTest.Supervisor.init.

We then manually fire up a new SupervisorTest.Supervisor by calling the associated start_link function. We notice [4, 5, 6, 7] is printed out again (which makes sense because we’re calling IO.inspect(args) in SupervisorTest.Supervisor.init). We then call Supervisor.which_children and (as expected) we see no started children. We then manually start the child process with a call to Supervisor.start_child and capture its pid.

We then call SupervisorTest.Server.get_pid(server), which sends a :get_pid call to server. We get back the supervisor’s pid, as expected. We then send a :stop message to the server, which stops the server. The next call to Supervisor.which_children shows that we successfullly restarted the process (as expected). We then call server = supervisor |> Supervisor.which_children |> Enum.at(0) |> elem(1) to capture the new server process and call get_pid, which returns the supervisor’s pid, as expected.

And that’s it. I hope you found this useful. Feel free to leave comments below.

Comment

Comments

входные двери с зеркалом металлические двери брак http://shpingalet-dverdoma.icu установка дверей в киеве установка межкомнатных дверей витебск http://door-roomhome.icu правильно установленная межкомнатная дверь кнопочный замок на входную дверь http://zavesi-furnituradverj.icu межкомнатные двери с врезанной фурнитурой производим металлические двери http://glazok-zasovzavesa.icu межкомнатные двери корона направляющие для межкомнатных дверей http://dom-zamok-dveri.icu

сборка межкомнатной двери запорный механизм балконной двери http://doorroomhome.icu металлопластиковые балконные двери цена железные двери москва и область http://shpingaletdver-doma.icu двери железные москва двери стальные входные металлические могилев http://dverj-zavesifurnitura.icu купить дверь входную в витебске купить входную дверь в беларуси http://home-doorroom.icu фиксатор балконной двери пвх купить двери пвх окна пвх http://dveri-domzamok.icu

Page 1

Back