Skip to content

Making rule engine execution order more deterministic #207

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 13, 2016

Conversation

mrrodriguez
Copy link
Collaborator

@mrrodriguez mrrodriguez commented Jul 12, 2016

Clara currently uses clara.rules.platform/tuned-group-by in a number of places. The grouping that this function does is unordered and often can vary from one JVM to the next. In particular I've noticed this happening in the clara.rules.engine/flush-updates which was causing non-deterministic insertion order to happen across rules. This makes it harder for us to track bad performance cases since they keep fluctuating as we run in different processes.

A side-effect of flush-updates not behaving deterministically was that insertion order across rules of the same salience group level were not deterministic and didn't necessarily respect rule load order as was implemented in #192. From my preliminary testing of this, I see a slight improvement in our execution times with this change in place. This is likely due to the rule order now also being the insertion order used. I've demonstrated this with a test that fails before this change and now passes.

My proposal is to (on the Java CLJ side) introduce a new clara.rules.platform/group-by-seq function that replaces the usages of platform/tuned-group-by. Currently, I've left platform/tuned-group-by in case it ends up having some usages later. It is also used in one CLJS place still, which I'm not wanting to change with this. platform/group-by-seq returns a seq of tuples, which is the same as seq'ing over the map returned by platform/tuned-group-by before. In all cases where we used platform/tuned-group-by we didn't use the map, but rather a seq over it.

I use a java.util.LinkedHashMap to maintain insertion order while building the groupings. Then I convert this into an immutable seq structure. If I tried to retain the usage of a map here, I'd have to return the java.util.LinkedHashMap or come up with some (expensive) way to port it into a Clojure sorted map. This was not worthwhile to me, since we do not need a map anyways. A java.util.LinkedHashMap would be harder to work with across the rest of the codebase since there are issues with the default Clojure seq implementations across mutable object iterators http://dev.clojure.org/jira/browse/CLJ-1738 that I see coming up when running this on JDK6 (oddly not on JDK8, which makes no sense and I want to investigate more for my own benefit).

Along with this, since I was messing with the clara.rules.compiler/create-get-alphas-fn already, I sorted the result of the ancestors-fn so that it would behave deterministically. This would be more of an edge case, but since we cache this result and infrequently should hit this path, I figured it'd still be worthwhile.

@rbrush
Copy link
Contributor

rbrush commented Jul 12, 2016

Looks good to me after an early review. I'll merge later today unless there are unexpected problems.

@WilliamParker
Copy link
Collaborator

I'll plan to look at this today.

;; by the :node-id of their :children.
new-nodes (sort-by #(mapv :node-id (:children %))
(into []
(comp (map #(get (get merged-rules :alpha-roots) %))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think this might be a bit more readable if you let-bound

(get merged-rules :alpha-roots)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do that.

@WilliamParker
Copy link
Collaborator

+1 apart from my comments.

@mrrodriguez
Copy link
Collaborator Author

mrrodriguez commented Jul 13, 2016

I've addressed all of the review comments made by @WilliamParker and updated this PR

- Added `platform/group-by-seq` to (mostly) replace `platform/tuned-group-by`
- Made ancestors-fn contribution to the alphas-fn map behave deterministically
@WilliamParker
Copy link
Collaborator

+1

@rbrush rbrush merged commit 13537db into oracle-samples:master Jul 13, 2016
@rbrush
Copy link
Contributor

rbrush commented Jul 13, 2016

Merged. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants