The docs don't say anything about what happens if an agent error
handler itself throws an exception, but the answer seems to be:
absolutely nothing.

=> (def a (agent 1))
#'bar/a
=> (set-error-handler! a (fn [_ err]
                           (if (instance? ArithmeticException err)
                             (throw (IllegalArgumentException.))
                             (println err))))
nil
=> (set-error-mode! a :continue)
nil
=> (send a inc)
#<Agent@1a5f0f3: 2>
=> (send a #())
#<IllegalArgumentException java.lang.IllegalArgumentException: Wrong
number of args (1) passed to: bar$eval1220$fn>
#<Agent@1a5f0f3: 2>
=> (send a / 0)
#<Agent@1a5f0f3: 2>
=> (send a inc)
#<Agent@1a5f0f3: 3>

As you can see, after the / 0 send, it just quietly continues to
accept messages such as inc without anything happening. If the error
handler had recursed on itself with the IAE as the err this time, it
would have printed #<IllegalArgumentException
java.lang.IllegalArgumentException>. Neither did the agent enter a
failed state. It looks like the IAE thrown (but not caught) inside the
error handler was simply swallowed.

If this is the desired behavior it should probably be documented.
Recursing of course would carry the risk of an infinite loop (though I
carefully constructed my test so it could not produce such a loop) and
failing the agent would violate expectations for an agent set to error
mode :continue, so it probably is the desired behavior.

The docs also aren't explicit about what thread the error handler is
called on, but the obvious implementation, namely (try (apply
next-queued-action @this args) (catch Throwable t (error-handler this
t))) (with a :fail agent having a handler that sets the agent's state
to failed and stores the throwable), would make it the agent thread,
and this experiment seems to bear out that guess:

=> (set-error-handler! a (fn [_ _] (println (Thread/currentThread))))
nil
=> (send a / 0)
#<Thread Thread[pool-1-thread-1,5,main]>
#<Agent@1a5f0f3: 3>

On the other hand:

=> (def b (agent 1))
#'bar/b
=> (set-error-handler! b (fn [_ _] (println (Thread/currentThread))))
nil
=> (send b / 0)
#<Thread Thread[pool-1-thread-2,5,main]>
#<Agent@15dbaab: 1>
=> (send b inc)
#<CompilerException java.lang.RuntimeException: Agent is failed, needs
restart (NO_SOURCE_FILE:0)>

points to something closer to (try (apply ...) (catch ...
(error-handler this t) (if (= mode :fail) (fail-me this t))) as the
actual implementation. I could dive into the source code now and see,
but I'm out of time for now. :)

-- 
Protege: What is this seething mass of parentheses?!
Master: Your father's Lisp REPL. This is the language of a true
hacker. Not as clumsy or random as C++; a language for a more
civilized age.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to