~udia/servy

72a156c7175f6d24bf811df77874e202667b1144 — Alexander Wong 1 year, 11 months ago 890a030
Fault Recovery with OTP Supervisors
M README.md => README.md +25 -0
@@ 1011,3 1011,28 @@ iex> pid = Task.async(fn -> raise "Kaboom!" end)
    ** (RuntimeError) Kaboom!
```

### Fault Recovery with OTP Supervisors

Supervisors are special processes that that are hierarchical parents of GenServer processes and other supervisors.
If a GenServer terminates, the Supervisor can restart the GenServer.


#### Restart Strategies

One of the options that can be passed into `Supervisor.init` is `strategy`:
* `:one_for_one`: if a child process terminates, only that process is restarted.
* `:one_for_all`: if a child process terminates, all children processes are restarted
* `:rest_for_one`: if a child process terminates, the rest of the child processes (children listed after the terminated child) that were started after it are terminated. All terminated children are then restarted.
* `:simple_one_for_one`: restricted to when a supervisor has one child specification. Used for dynamically spawning child procsses that are then attached to the supervisor (ie a pool of similar worker processes).

Additional options are:

* `:max_restarts`: indicates max number of restarts allowed within a given time frame (default is 3 restarts)
* `:max_seconds`: indicates the time frame for `:max_restarts` (default is 5 seconds)

```elixir
opts = [strategy: :one_for_one, max_restarts: 5, max_seconds: 10]

# These children will be supervised with the one_for_one strategy, allowing 5 restarts within 10 seconds before error occurs.
Supervisor.init(children, opts)
```

M lib/servy/kickstarter.ex => lib/servy/kickstarter.ex +2 -2
@@ 1,9 1,9 @@
defmodule Servy.KickStarter do
  use GenServer

  def start do
  def start_link(_arg) do
    IO.puts("Starting the kickstarter...")
    GenServer.start(__MODULE__, :ok, name: __MODULE__)
    GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
  end

  def init(:ok) do

M lib/servy/pledge_server.ex => lib/servy/pledge_server.ex +11 -2
@@ 20,12 20,21 @@ defmodule Servy.PledgeServer do
    defstruct cache_size: 3, pledges: []
  end

  # can also be overried in the `use GenServer`
  # def child_spec(_arg) do
  #   %{
  #     id: Servy.PledgeServer,
  #     restart: :temporary,
  #     start: {Servy.PledgeServer, :start_link, [[]]}
  #   }
  # end

  # Client interface functions

  def start do
  def start_link(_arg) do
    IO.puts("Starting the pledge server")
    # second argument is passed to init/1
    GenServer.start(__MODULE__, %State{}, name: @name)
    GenServer.start_link(__MODULE__, %State{}, name: @name)
  end

  def create_pledge(name, amount) do

M lib/servy/sensor_server.ex => lib/servy/sensor_server.ex +4 -3
@@ 1,13 1,14 @@
defmodule Servy.SensorServer do
  @name :sensor_server
  @refresh_interval :timer.seconds(5)  # :timer.minutes(60)
  @refresh_interval :timer.minutes(60) # :timer.seconds(5)

  use GenServer

  # Client Interface

  def start do
    GenServer.start(__MODULE__, %{}, name: @name)
  def start_link(interval) do
    IO.puts "Starting the sensor server with #{interval} arg refresh..."
    GenServer.start_link(__MODULE__, %{}, name: @name)
  end

  def get_sensor_data do

A lib/servy/services_supervisor.ex => lib/servy/services_supervisor.ex +17 -0
@@ 0,0 1,17 @@
defmodule Servy.ServicesSupervisor do
  use Supervisor

  def start_link(_arg) do
    IO.puts "Starting the services supervisor..."
    Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)
  end

  def init(:ok) do
    children = [
      Servy.PledgeServer,
      {Servy.SensorServer, 60}
    ]

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

A lib/servy/supervisor.ex => lib/servy/supervisor.ex +17 -0
@@ 0,0 1,17 @@
defmodule Servy.Supervisor do
  use Supervisor

  def start_link do
    IO.puts "Starting THE supervisor..."
    Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)
  end

  def init(:ok) do
    children = [
      Servy.KickStarter,
      Servy.ServicesSupervisor
    ]

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