vinhnglx / vinhnglx.github.io

0 stars 0 forks source link

TIL_10_July_2017 - Fault Tolerance and Supervisor in Elixir #19

Open vinhnglx opened 7 years ago

vinhnglx commented 7 years ago

Regardless of which part of the system happens to fail, you shouldn't take down the entire system. Your priority should be to minimize their effects, isolate errors and recover from them automatically.

Fault Tolerance is a first-class concept in Erlang/Elixir. Below are basic techniques of detecting and handling errors in a concurrent system.

vinhnglx commented 7 years ago

There are three types of runtime errors: errors, exits and throw.

iex(1)> 1/0
** (ArithmeticError) bad argument in arithmetic expression
    :erlang./(1, 0)
iex(1)> Hello.nonexistence_function
** (UndefinedFunctionError) function Hello.nonexistence_function/0 is undefined (module Hello is not available)
    Hello.nonexistence_function()
iex(1)> {1,2,3,4} |> List.first
** (FunctionClauseError) no function clause matching in List.first/1
    (elixir) lib/list.ex:219: List.first({1, 2, 3, 4})
iex(1)> raise "hell"
** (RuntimeError) hell
# without exit
iex(2)> spawn(fn ->
...(2)> IO.puts "Whew"
...(2)> end)
Whew
#PID<0.93.0>

# with exit
iex(1)> spawn(fn ->
...(1)> exit("I'm done")
...(1)> IO.puts "Whew"
...(1)> end)
#PID<0.89.0>
vinhnglx commented 7 years ago
try do
   ....
catch error_type, error_value ->
  ...
end
vinhnglx commented 7 years ago
vinhnglx commented 7 years ago

How to handle the error in the concurrent system.

Because processes share no memory, a crash in one process won't leave memory garbage that might corrupt another process.

But, in fact, processes often communicate with each other. Therefore, we have a way of detecting a process crash and somehow recovering from it.

If two process are linked and one of them terminates, the other process receives an exit signal - a notification that a process has crashed.

An exit signal contains the PID of the crashed process and the exit reason. By default, when a process receives an exit signal from another process, the linked process terminates as well.

One link connects exactly two processes and is always bidirectional.

Use Process.link/1: Creates a link between the calling process and another process. Or we can use spawn_link which spawns a process and links it to the current one.

One process can be linked to an arbitrary number of other processes. Hence, if the default behavior isn't overridden, then those processes will crash as well

vinhnglx commented 7 years ago

When a process is trapping exits, it isn’t taken down when a linked process crashes. Instead, an exit signal is placed in the surviving process's message queue, in the form of a standard message. A trapping process can receive these messages and do something about the crash.

Call Process.flag/2 or Process.flag/3 to setup an exit trap.

vinhnglx commented 7 years ago

Use Process.monitor/1: the calling process starts monitoring the given item. It returns the monitor reference.

A single process can create multiple monitors.

vinhnglx commented 7 years ago

There are two main differences between monitors and links.

vinhnglx commented 7 years ago

Supervisor

The idea behind Supervisor is simple. Each worker process is supervised by a supervisor process. Whenever a worker process terminates, the supervisor starts another one in its place. The supervisor basically does nothing but supervise, which makes its code simple, error-free and thus unlikely to crash.

A Supevisor work-follow:

vinhnglx commented 7 years ago