So you just got into building rules and you finally got something to work, when suddenly you hear your laptop fan start spinning out of control. You have no idea what is going on and suddenly you are unable to do anything, your laptop becomes completely unresponsive. All you remember is that the last thing you did was execute a set of business rules running on your local application server, whether JBoss/WildFly or Tomcat.
Well, the chances are good that you just hit your first infinite loop! This is part three of a three part blog post that covers how to detect an infinite loop in your rules and how to auto recover:
- Part 1 - How to detect an infinite loop in your BRMS Rules
- Part 2 - How to prevent an Infinite loop
- Part 3 - How to Automatically detect an Infinite loop and exit the Rules Engine
How to automatically detect an infinite loop and exit the Rules Engine
Now, if you know you have an infinite loop and you know which rules are causing it, you can definitely do something about it, but what can you do to be prepared for that day when it creeps into your rules and shows its head unexpectedly? The following is a trick that you can use to automatically stop and exit the rules engine:
Code Block 11 - Exit Rules Engine
In Code Block 11 above, we created a rule that does not belong to any specific agenda group but with a high salience (priority) on line 3 and a timer for three seconds on line 2. Also note that there are no conditions on the LHS, so this rule will be activated after three seconds of the initial execution of the rules engine (call to fireAllRules() method) no matter what. On line 7 in the RHS of the rule, it will call the halt method of the rules engine, which will terminate all rule executions and exit the rules engine. What is so special about the three seconds? Well, this is where you will have to experiment with your rules engine execution time and find out how long it takes under normal conditions to fire all your rules. Small rule projects take on average a couple of milliseconds where larger rule projects can take hundreds of milliseconds. To be on the safe side, always double or triple the average rule execution time and use that for the timer in the auto exit rule. This way, you will not prematurely exit the rules engine before all rules fired. Under normal conditions, this rule will never be activated. But the moment you hit an infinite loop, the rules engine will never exit, so in the latter case the auto exit rule will be activated and save the day before things get out of hand.
There is also another way you can force an auto exit of the rules engine. The method fireAllRules() has an over loaded method fireAllRules(int max), that takes an integer max, which is the maximum number of allowable rule activations/matches, before exiting the rules engine and return control to the application. Again, you will have to play with your rules engine under normal conditions and figure out what the average number of rule matches are and then double or triple it to make sure you do not prematurely exit the rule execution process.
How to notify the outside world when an infinite loop is detected
The expectation is that by the end of a rules project, most rule execution issues would have been resolved. However, there is always the case where a new change was introduced at the last minute that can produce an infinite loop situation. With good regression testing, this possibility can be minimized but wouldn't it be useful if we can create some kind of notification when the application suspects that something fishy is going on and that the rules engine is not exiting normally but via our special rule with its timer (mentioned in the previous section). This way, developers can be notified early and can look into the issue right away, instead of days or weeks later when customers or users start to complain about irregularities in the outcome of the rules being executed. To create this early warning system, we can make use of an AgendaEvenListener as shown in Code Block 12. Here, we created a new AgendaListener class implementing the org.kie.api.event.rule.AgendaEventListener and implementing the interface method afterMatchFired(). Now, look closely at line 6. The code is checking for a very specific rule (in our case the auto exit rule). If it detects that the rule was fired, it prints a warning message to the server log. Here is the perfect place to add additional code to trigger an email notification or any other type of message that will alert someone that something is not right.
Code Block 12 - Agenda Listener
Now, to add the Agenda Listener to the rules engine, you need to register it first before you execute the rules. To do this, make use of the method addEventListener() of the KIE Session as shown in Code Block 13:
Code Block 13 - Register Agenda Listener
That is all there is to it.
I hope you find this post helpful, and that you can use this information to get a better handle on infinite loops.
Please leave a comment below and let me know what you think. If you are looking for Drools consulting services please contact us to schedule a complimentary consultation.