DEV Community

Vinicius Moreira
Vinicius Moreira

Posted on

9 4

Testando os tipos de Strategy do Supervisor do Elixir

Vamos testar o comportamento dos 3 tipos de Strategy:

  • :one_for_one (Se um processo filho terminar, apenas este processo será reiniciado)
  • :one_for_all (Se um processo filho terminar, todos os outros filhos serão terminados e depois, todos os processos seráo reiniciados, inclusive, o processo que terminou)
  • :rest_for_one (Se um processo filho terminar, todos os filhos que foram criados depois dele serão finalizados e os mesmos serão reiniciados, inclusive, o processo que terminou)

mix new test_otp --sup

Image description

Testando :one_for_one

Vamos configurar no application para os processos sejam criados nessa orderm:

ProcessA
ProcessB
ProcessC

Vamos iniciar cada processo com o estado: [0]

Por padrão, o strategy: já vem como :one_for_one

test_otp/application.ex

defmodule TestOtp.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  @impl true
  def start(_type, _args) do
    children = [
      # Starts a worker by calling: TestOtp.Worker.start_link(arg)
      # {TestOtp.Worker, arg}
      Core.ProcessA,
      Core.ProcessB,
      Core.ProcessC
    ]

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

Enter fullscreen mode Exit fullscreen mode

criar o ProcessA

test_otp/core/process_a.ex

defmodule Core.ProcessA do
  use GenServer

  # Server

  @impl true
  def init(state) do
    {:ok, state}
  end

  @impl true
  def handle_call(:get, _from, state) do
    {:reply, state, state}
  end

  @impl true
  def handle_cast({:add, items}, state) do
    {:noreply, state ++ items}
  end

  # Client

  def start_link(_) do
    GenServer.start_link(__MODULE__, [0], name: ProcessA)
  end

  def get() do
    GenServer.call(ProcessA, :get)
  end

  def add() do
    GenServer.cast(ProcessA, {:add, [1,2,3])
  end
end

Enter fullscreen mode Exit fullscreen mode

criar o ProcessB

test_otp/core/process_b.ex

defmodule Core.ProcessB do
  use GenServer

  # Server

  @impl true
  def init(state) do
    {:ok, state}
  end

  @impl true
  def handle_call(:get, _from, state) do
    {:reply, state, state}
  end

  @impl true
  def handle_cast({:add, items}, state) do
    {:noreply, state ++ items}
  end

  # Client

  def start_link(_) do
    GenServer.start_link(__MODULE__, [0], name: ProcessB)
  end

  def get() do
    GenServer.call(ProcessB, :get)
  end

  def add() do
    GenServer.cast(ProcessB, {:add, [4,5,6])
  end
end

Enter fullscreen mode Exit fullscreen mode

criar o ProcessC

test_otp/core/process_c.ex

defmodule Core.ProcessC do
  use GenServer

  # Server

  @impl true
  def init(state) do
    {:ok, state}
  end

  @impl true
  def handle_call(:get, _from, state) do
    {:reply, state, state}
  end

  @impl true
  def handle_cast({:add, items}, state) do
    {:noreply, state ++ items}
  end

  # Client

  def start_link(_) do
    GenServer.start_link(__MODULE__, [0], name: ProcessC)
  end

  def get() do
    GenServer.call(ProcessC, :get)
  end

  def add() do
    GenServer.cast(ProcessC, {:add, [4,5,6])
  end
end

Enter fullscreen mode Exit fullscreen mode

Vamos iniciar a aplicaçao com o IEX

iex -S mix

Dentro do IEX, vamos digitar

Core.ProcessA.add
Core.ProcessB.add
Core.ProcessC.add

Depois, vamos conferir o estado dos processos:

Core.ProcessA.get
[0,1,2,3]
Core.ProcessB.add
[0,4,5,6]
Core.ProcessC.add
[0,7,8,9]

Image description

Agora, vamos parar o ProcessB

Digite no IEX

GenServer.stop(ProcessB)

Agora, vamos conferir o estado dos processos:

Core.ProcessA.get
[0,1,2,3]
Core.ProcessB.add
[0]
Core.ProcessC.add
[0,7,8,9]

Image description

Percebemos que apenas o ProcessB voltou ao estado inicial, ou seja, apenas ele foi reiniciado.

Testando :one_for_all

Para isso, vamos mudar apenas o strategy: no arquivo test_otp/application.ex, vamos colocar strategy: :one_for_all

test_otp/application.ex

defmodule TestOtp.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  @impl true
  def start(_type, _args) do
    children = [
      # Starts a worker by calling: TestOtp.Worker.start_link(arg)
      # {TestOtp.Worker, arg}
      Core.ProcessA,
      Core.ProcessB,
      Core.ProcessC
    ]

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

Enter fullscreen mode Exit fullscreen mode

Vamos iniciar a aplicaçao com o IEX

iex -S mix

Dentro do IEX, vamos digitar

Core.ProcessA.add
Core.ProcessB.add
Core.ProcessC.add

Depois, vamos conferir o estado dos processos:

Core.ProcessA.get
[0,1,2,3]
Core.ProcessB.add
[0,4,5,6]
Core.ProcessC.add
[0,7,8,9]

Image description

Agora, vamos parar o ProcessB

Digite no IEX

GenServer.stop(ProcessB)

Agora, vamos conferir o estado dos processos:

Core.ProcessA.get
[0]
Core.ProcessB.add
[0]
Core.ProcessC.add
[0]

Image description

Percebemos que todos os processos voltaram ao estado inicial, ou seja, todos foram finalizados e reiniciados.

Testando :rest_for_one

Vamos mudar apenas o strategy: no arquivo test_otp/application.ex, vamos colocar strategy: :rest_for_one

test_otp/application.ex

defmodule TestOtp.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  @impl true
  def start(_type, _args) do
    children = [
      # Starts a worker by calling: TestOtp.Worker.start_link(arg)
      # {TestOtp.Worker, arg}
      Core.ProcessA,
      Core.ProcessB,
      Core.ProcessC
    ]

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

Enter fullscreen mode Exit fullscreen mode

Vamos iniciar a aplicaçao com o IEX

iex -S mix

Dentro do IEX, vamos digitar

Core.ProcessA.add
Core.ProcessB.add
Core.ProcessC.add

Depois, vamos conferir o estado dos processos:

Core.ProcessA.get
[0,1,2,3]
Core.ProcessB.add
[0,4,5,6]
Core.ProcessC.add
[0,7,8,9]

Image description

Agora, vamos parar o ProcessB

Digite no IEX

GenServer.stop(ProcessB)

Agora, vamos conferir o estado dos processos:

Core.ProcessA.get
[0,1,2,3]
Core.ProcessB.add
[0]
Core.ProcessC.add
[0]

Image description

Percebemos que apenas o ProcessB e o ProcessC) voltaram ao estado inicial. O ProcessB foi parado, por isso, foi reiniciado, já o ProcessC, que foi criado depois do ProcessB, vejam no arquivo application.ex, foi finalizado e reiniciado. E o ProcessA, que foi criado antes do ProcessB, manteve o seu estado, ou seja, não foi reiniciado.

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (2)

Collapse
 
theguuholi profile image
Elxpro

Excelente artigo!! Excelente forma de apresentar a ideia, mais simples que isso. Quase impossivel :D

Collapse
 
lcezermf profile image
Luiz Cezer

Simples e assertivo na explicação, muito bom!

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs