Recovering from errors in agents

Since agents run in a thread pool, the way exceptions are signaled and handled becomes an issue. Does the offending message function simply stop running? Does the agent stop? What happens to the Exception instance?

Clojure has several mechanisms to deal with errors in agent functions. We'll walk through them in this recipe.

How to do it…

The agent's error mode and error handler determine how it handles errors. The error mode can be set when the agent is created or with the function set-error-mode!, and the error handler is set with set-error-handler!.

Failing on errors

The default error mode is :fail. If we don't specify an error mode when we create an agent, this is what it gets. With this error mode, when one of the agent's message functions throws an exception, the agent stops processing any more messages and stores the exception. We can retrieve the exception with agent-error, and we can start processing it again with restart-agent:

user=> (def agent-99 (agent 0))
#'user/agent-99
user=> (send agent-99 #(/ 100 %))
#<Agent@aa711 FAILED: 0>
user=> (agent-error agent-99)
#<ArithmeticExceptionjava.lang.ArithmeticException: Divide by zero>
user=> @agent-99
0
user=> (restart-agent agent-99 0)
0

Continuing on errors

The other option for an error mode is :continue. With this error mode, when an agent throws an exception, the exception and the message that caused it are silently swallowed. The agent continues processing as if nothing has happened:

user=> (def agent-99 (agent 0 :error-mode :continue))
#'user/agent-99
user=> (send agent-99 #(/ 100 %))
#<Agent@f1b6fa6: 0>
user=> (agent-error agent-99)
nil
user=> @agent-99
0

Using a custom error handler

If the agent's error handler is set, that is used instead of the error mode. The error handler is just a function that is called with the agent and the exception that was thrown. In this example, the new error handler will simply print the exception:

user=> (def agent-99 (agent 0 :error-handler #(prn %2)))
#'user/agent-99
user=> (send agent-99 #(/ 100 %))
#<ArithmeticExceptionjava.lang.ArithmeticException: Divide by zero>
#<Agent@2da13aa9: 0>
user=> (agent-error agent-99)
nil
user=> @agent-99
0

Once an error has been caught using a custom error handler, the agent is free to continue processing. If we send agent-99 a new message, it will process it as if nothing has happened.

There's more...

The canonical source of information about Clojure's agent system and how it handles errors is the Agents and Asynchronous Actions page in the Clojure documentation at http://clojure.org/agents.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.21.158