240 likes | 254 Views
Computer Science 312. Concurrent Programming III Handling Errors in Concurrent Programming. Run-Time Errors. Examples: No clauses in a function match Wrong type of operand to built-in functions Exceptions are raised but can be caught. Raising Exceptions.
E N D
Computer Science 312 Concurrent Programming III Handling Errors in Concurrent Programming
Run-Time Errors • Examples: • No clauses in a function match • Wrong type of operand to built-in functions • Exceptions are raised but can be caught
Raising Exceptions • exit(Why) – used to quit the program, but can be caught; we’ll see this more in concurrent programs • throw(Why) – intended to be caught, should be documented in our code • erlang:error(Why) – bad crashing errors, not usually caught
try/catch/after Syntax try ExpressionSeq of Pattern1 [when Guard1] -> Expresions1; Pattern2 [when Guard2] -> Expresions2; . . . catch ExceptionType1:ExPattern1 [when ExGuard1] -> Exps1; ExceptionType2:ExPattern2 [when ExGuard2] -> Exps2; . . . after AfterExpressions end Like a case expression on steroids
Simpler Form try ExpressionSeq catch ExceptionType1:ExPattern1 -> Exps1; ExceptionType2:ExPattern2 -> Exps2; . . . end
A Simple Example % testex.erl -module(testex). -export([divide/2]). divide(X, Y) -> try X / Y catch throw:ExValue -> {X, Y, thrown, ExValue}; error:ExValue -> {X, Y, error, ExValue} end.
A Simple Example % testex.erl -module(testex). -export([divide/2]). divide(X, Y) -> try X / Y catch throw:ExValue -> {X, Y, thrown, ExValue}; error:ExValue -> {X, Y, error, ExValue} end. 2> testex:divide(3, 0). {3,0,error,badarith} 3> 3 / 0. ** exception error: an error occurred when evaluating an arithmetic expression in operator '/'/2 called as 3 / 0
Catching All Exceptions % testex.erl -module(testex). -export([divide/2]). divide(X, Y) -> try X / Y catch _:_ -> {X, Y, allErrors} end.
Let ‘em fail! • When an error occurs in a sequential program, we catch it and recover or degrade gracefully • When an error occurs in a concurrent process, we let the process die • Someone (another process) will notice this demise, and respond appropriately
Concepts for Concurrent Error Handling • Links – allow one process to monitor another for failure • Exit signals – messages that are transmitted when a process fails • System processes – processes that don’t die when they receive an exit signal
Ways to Die • Normally – when a process reaches the end of the function executing in it • Abnormally – when the process generates a system error or when it raises its own error explicitly
Links • Establish error propagation paths between processes • Allow one or more processes to monitor another process for failure • If a process dies, Erlang sends an exit signal to its entire link set (all of the processes linked to it)
Linked Processes and Failure Before P9 dies abnormally After P9 and its linked processes die
Exit Signal • A message is sent to the link set of a process when it dies • The message contains an Erlang term that represents the cause of death • Can use exit(Reason) to explicitly set this argument • Or allow the default argument, usually an error type, to be sent automatically • When a process terminates normally, is dies with the reason normal
System Process • If a process receives a non-normal exit signal, it dies too, unless it is a system process • When a system process receives such a message, it comes in the form {'exit', Pid, Why} • Calling process_flag(trap_exit, true) converts the calling process into a system process • Trapping can be overridden with the kill reason
Putting a Firewall on a Process Before P9 dies P3 is a system process After P9 and linked non-system processes die
Exit Trapping Idioms: No Link I want to keep running if my spawn dies abnormally: Pid = spawn(fun() -> . . . end)
Exit Trapping Idioms: Link and Die I want to keep running if my spawn dies abnormally: Pid = spawn(fun() -> . . . end) I want to link to my spawn, so I also die if my spawn dies abnormally: Pid = spawn_link(fun() -> . . . end)
Exit Trapping Idioms: Link and Trap Links as a system process to Pid and runs fun if Pid dies: % in lib_misc.erl on_exit(Pid, Fun) -> spawn(fun() -> process_flag(trap_exit, true), link(Pid), receive {'EXIT', Pid, Why} -> Fun(Why) end end).
Exit Trapping Idioms: Link and Trap Links as a system process to Pid and runs fun if Pid dies: 1> Bad_func = fun() -> receive Message -> list_to_atom(Message) end end. 2> Pid = spawn(Bad_func). 3> lib_misc:on_exit(Pid, fun(Why) -> io:format(" ~p died with:~p~n", [Pid, Why]) end). 4> Pid ! hello.
Exit Trapping Idioms: Monitoring Links as a monitor (not a system process) to Pid and runs fun if Pid dies: % in lib_misc.erl on_exit(Pid, Fun) -> spawn(fun() -> Ref = monitor(process, Pid), receive {'DOWN', Ref, Pid, process, Why} -> Fun(Why) end end).
A Process That Never Dies Restart a process as soon as it dies! % in lib_misc.erl keep_alive(Name, Fun) -> register(Name, Pid = spawn(Fun)), on_exit(Pid, fun(_Why) -> keep_alive(Name, Fun) end).
Fault Tolerance • In a fault-tolerant system, if a process running on one computer fails, a process running on another computer notices and takes over • This common pattern is called the worker-supervisor model • A fault-tolerant system consists of processes organized in a supervision tree
For next time File processing