\section{Management \& Error Detection}

\lib adapts Erlang's well-established fault propagation model.
It allows to build actor subsystem in which either all actors are alive or have collectively failed.

\subsection{Links}

Linked actors monitor each other.
An actor sends an exit message to all of its links as part of its termination.
The default behavior for actors receiving such an exit message is to die for the same reason, if the exit reason is non-normal.
Actors can \textit{trap} exit messages to handle them manually.

\begin{lstlisting}
actor worker = ...;
// receive exit messages as regular messages
self->trap_exit(true);
// monitor spawned actor
self->link_to(worker);
// wait until worker exited
self->become (
  [=](const exit_msg& e) {
    if (e.reason == exit_reason::normal) {
      // worker finished computation
    else {
      // worker died unexpectedly
    }
  }
);
\end{lstlisting}

\subsection{Monitors}
\label{Sec::Management::Monitors}

A monitor observes the lifetime of an actor.
Monitored actors send a down message to all observers as part of their termination.
Unlike exit messages, down messages are always treated like any other ordinary message.
An actor will receive one down message for each time it called \lstinline^self->monitor(...)^, even if it adds a monitor to the same actor multiple times.

\begin{lstlisting}
actor worker = ...;
// monitor spawned actor
self->monitor(worker);
// wait until worker exited
self->become (
  [](const down_msg& d) {
    if (d.reason == exit_reason::normal) {
      // worker finished computation
    } else {
      // worker died unexpectedly
    }
  }
);
\end{lstlisting}

\subsection{Error Codes}

All error codes are defined in the namespace \lstinline^caf::exit_reason^.
To obtain a string representation of an error code, use \lstinline^caf::exit_reason::as_string(uint32_t)^.

\begin{tabular*}{\textwidth}{m{0.35\textwidth}m{0.08\textwidth}m{0.5\textwidth}}
  \hline
  \lstinline^normal^ & 1 & Actor finished execution without error \\
  \hline
  \lstinline^unhandled_exception^ & 2 & Actor was killed due to an unhandled exception \\
  \hline
  \lstinline^unhandled_sync_failure^ & 4 & Actor was killed due to an unexpected synchronous response message \\
  \hline
  \lstinline^unhandled_sync_timeout^ & 5 & Actor was killed, because no timeout handler was set and a synchronous message timed out \\
  \hline
  \lstinline^unknown^ & 6 & Indicates that an actor has been exited and its state is no longer known \\
  \hline
  \lstinline^out_of_workers^ & 7 & Indicates that an actor pool unexpectedly ran out of workers \\
  \hline
  \lstinline^user_shutdown^ & 16 & Actor was killed by a user-generated event \\
  \hline
  \lstinline^kill^ & 17 & Unconditionally kills actors when using in an \lstinline^exit_msg^, even when trapping exits \\
  \hline
  \lstinline^remote_link_unreachable^ & 257 & Indicates that a remote actor became unreachable, e.g., due to connection error \\
  \hline
  \lstinline^user_defined^ & 65536 & Minimum value for user-defined exit codes \\
  \hline
\end{tabular*}

\subsection{Attach Cleanup Code to an Actor}

Actors can attach cleanup code to other actors.
This code is executed immediately if the actor has already exited.

\begin{lstlisting}
using done_atom = atom_constant<atom("done")>;

behavior supervisor(event_based_actor* self, actor worker) {
  actor observer = self;
  // "monitor" spawned actor
  worker->attach_functor([observer](std::uint32_t reason) {
    // this callback is invoked from worker
    anon_send(observer, done_atom::value);
  });
  // wait until worker exited
  return {
    [](done_atom) {
      // ... worker terminated ...
    }
  };
}
\end{lstlisting}

\textbf{Note}: It is possible to attach code to remote actors, but the cleanup code will run on the local machine.
