Fork me on GitHub
#clara
<
2017-05-01
>
enn15:05:04

Can anyone suggest how I might instrument my rules to figure out which one is throwing an NPE? The NPE is during > during an accumulator’s reduction which makes me assume it’s the max accumulator, which I use in only a handful of rules. I’d like to narrow down which specifically is throwing the exception, but I’m not sure how I’d go about putting logging in the LHS of a rule. (The RHS is too late as the accumulators are used only in LHSs.)

zylox16:05:07

do you have an example stack trace?

wparker17:05:54

@enn unfortunately errors during accumulation aren’t handled as well as errors in non-accumulator conditions; https://github.com/cerner/clara-rules/issues/265 is logged to improve that (non-accumulator conditions were improved in https://github.com/cerner/clara-rules/issues/255 )

wparker17:05:48

In the meantime your best option is probably to wrap the accumulator in question in a way that indicates what rules you’re in when it throw an exception

wparker17:05:45

Clara accumulators are just maps containing functions, and the accumulator can be modified by adding a new value onto one of the keys

wparker17:05:03

Your stacktrace tells me you’re throwing in the reduce-fn

wparker17:05:08

So you could do something like (defn ->wrapped-reduce-fn [original-reduce-fn rule-name] (fn [& args] (try (apply original-reduce-fn args) (catch Exception e (throw (ex-info (str “Threw exception in accumulation in ” rule-name) {} e))))

wparker17:05:34

and (defrule [?result-binding <- (update (acc/min :field) :reduce-fn ->wrapped-reduce-fn rule-name) …

wparker17:05:27

actually to work with the update you’d need to reverse the args order of ->wrapped-reduce-fn, but that is the basic idea

wparker17:05:12

The problem with tracing is that when you throw an exception and exit the rules firing loop you’ll lose the transient listener that has the info you want

wparker17:05:41

When a RHS exception is thrown we call to-persistent on the listeners but that won’t happen in an exception during accumulation https://github.com/cerner/clara-rules/blob/master/src/main/clojure/clara/rules/engine.cljc#L1787

wparker17:05:17

You could write your own listener that had global side effects or some such to get around that if you wanted though

wparker17:05:36

There are some docs on what the different accum function fields do at http://www.clara-rules.org/docs/accumulators/, you can also look at the structures created at https://github.com/cerner/clara-rules/blob/master/src/main/clojure/clara/rules/accumulators.cljc

enn17:05:17

Thank you, the wrapping idea makes sense

enn17:05:09

though a little clunky as we are not specifying the reduce-fn directly (it’s created via acc/max and comparison-based)

wparker18:05:16

Yeah, it is clunky, but hopefully if you have just a handful of rules and a particular exception it won’t be too bad. Obviously not as nice as having built-in error handling i.e. issue 265 but hopefully solves your immediate need