Testando os tipos de Strategy do Supervisor do Elixir
Tags: elixir, genserver, supervisor
Published: 2022-06-24 01:00:22

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pwc9etcg3zdu8b4s3gbw.png)
 


## 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

```

**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

```

**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

```


**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

```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8rq9095gy5el23mu1eo.png) 

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ek0lnrbgqbutglvihyew.png) 
 
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

```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m2u54shmdu9v0df7xlu0.png) 

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zw6lut33sfddlkjerpqd.png)
 

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

```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8rq9095gy5el23mu1eo.png) 

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/plzw6nbpnbmi8a8y9vp4.png) 

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.