Using Business Rules Engine "Update" for Forward Chaining
Fitting that my 100th post is on the same topic as one of my first, the Business Rules Engine.
The other day I had a customer ask me about a problem they had while executing a business rule on a repeating element where the result
was not what they expected. The scenario consisted of multiple address nodes with an element called OptOutDays. The role of the business rule
was to evaluate each Address/OptOutDays and store the largest one in a root-level field called TempOptOutDays.
For instance, I have an XML input instance (see below) that has three address lines, and OptOutDays of 170, 120, and 100. So the rule action had to update
the TempOptOutDays with the max amount, in this case, 170.
The problem was that this customer's TempOptOutDays value didn't contain highest OptOutDays amount. So I spent some time rebuilding their scenario, and discovered
that because they had not properly set up forward-chaining, the TempOptOutDays value was getting overwritten by each looping pass.
I wrote the rule you see in the picture below. Note that I use an Update action step so that I am telling the Business Rules Engine to
reevaluate the particular fact. In this case I'm passing in the parent element of the TempOptOutDays node, which is the root element.
So why did that matter? The BRE goes through three stages when executing policies: matching, conflict resolution and action. During the matching phase,
the execution agenda is populated by rules that match the conditions and input facts. During this particular matching instance, the BRE adds this rule to the agenda for
each "address" fact, since the default TempOptOutDays is 0, and each rule condition should fire (see picture below). It does NOT take into account that the rule's action
CHANGES that TempOptOutDays value from pass to pass, and therefore overwrites the value each time (treating it as 0). So, the Update forces the BRE
to intelligently reevaluate the rules and therefore always consider the CURRENT value of TempOptOutDays element.
I rewrote this a couple times, and it still reads back a bit confusing. But the moral of the story is, if you have forward-chaining scenarios, think
about how to efficiently update the facts in memory when the values of those facts drive other rules.