Open vinhnglx opened 7 years ago
errors
, exits
and throw
.errors
errors
raise
!
to each function that you want to explicitly raises an error. This is a convention in Elixir.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
exit
is used to deliberately terminate a process. # 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>
throw
allows non-local returns. When you are deep in a loop, throw
a value and catch it up the call stack is the way to stop the loop and return a value - shouldn't use ittry
construct to intercept and kind of run-time error and do something about it.try do
....
catch error_type, error_value ->
...
end
error_type
will contain an atom :error
, :exit
, or :throw
.catch
is a pattern match, multiple clauses can be specified.after
block is useful to clean up resourcesBecause 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
trapping exits
. 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.
Use Process.monitor/1
: the calling process starts monitoring the given item. It returns the monitor reference.
A single process can create multiple monitors.
There are two main differences between monitors and links.
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:
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.