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