Issue with Activation-group and reused session from pool

158 views
Skip to first unread message

michele

unread,
Aug 17, 2021, 5:47:11 AM8/17/21
to Drools Usage

Hello everyone,

 

we are using Drools (latest version 7.58.Final) and we are facing an error in our implementation using the session pool.

 

In our use case we need to run rules and to use Drools engine hundreds of thousond time in a few minutes (30 minutes more or less). The engine is used inside an architecture with Kafka and spring boot framework so our expectation is that the performance are very high.

 

We have in some rules the  activation-group option in order to fire and collect the result of only one rule with the same activation group (I mean the first one that is true and not considering the other rules).

 

We have noticed that when we change our implementation from one session creation to session pool to scale up our application (because we have notice that single session creation is a bottleneck), the activation group doesn’t work when the session is reused. Basically if we don’t use the pool we don’t have a problem with activation group, instead the if we create a pool (in both cases stateless or state full) for example with 10 initial instances, using the same input data, the first time the output is the expected one, for the second try the engine reuses the session from the pool and the output is not correct because in this scenario all rule are fired and we noticed that the activation group has no effect.

 

Has someone had the same problem? Is there something that we can check or change?

 

Thank for you support.

 

Michele

 

Luca Molteni

unread,
Aug 17, 2021, 6:00:23 AM8/17/21
to drools...@googlegroups.com
Hello Michele

it definitely sounds like an interaction bug between the session pool and the activation group.

I’ve also checked in the documentation and there is no trace of anything related.

Can you share with us a reproducer so that we can take a look at it? You can remove and obfuscate all the rules, we care only about the interaction

Thank you

Luca

michele

unread,
Aug 17, 2021, 10:22:39 AM8/17/21
to Drools Usage
Hi Luca, I try to explain the implementation here, if necessary I can try to create unit test:

-------Factory class created once when the spring boot context is started up---------------------------

@Component
public class DroolsBeanFactory {

private RuleService ruleService;
private KieServices kieServices = KieServices.Factory.get();
private KieBuilder kieBuilder;
private KieContainerSessionsPool pool;

@Autowired
public DroolsBeanFactory(RuleService ruleService) throws IOException {
this.RuleService = ruleService;
getKieRepository();
loadDrls();
pool = kieServices.newKieContainer(kieBuilder.getKieModule().getReleaseId()).newKieSessionsPool( 2 );
}

private void getKieRepository() {
final KieRepository kieRepository = kieServices.getRepository();
kieRepository.addKieModule(new KieModule() {
public ReleaseId getReleaseId() {
return kieRepository.getDefaultReleaseId();
}
});
}

private void loadDrls() {
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();

List<SmeRetailRule> ruleList = ruleService.getRules(); //Uploaded from DB
ruleList.stream()
.filter(rule -> rule.getContent() != null)
.filter(rule -> RuleType.DROOLS.getCode().equals(rule.getType()))
.forEach((rule -> {
Reader drlFileReader = new StringReader(rule.getContent());
kieFileSystem.write("src/main/resources/Rule" + rule.getId() + ".drl", ResourceFactory.newReaderResource(drlFileReader));
}));

kieBuilder = kieServices.newKieBuilder(kieFileSystem);
kieBuilder.buildAll();

Results results = kieBuilder.getResults();
if (results.hasMessages(Message.Level.ERROR)) {
throw new IllegalStateException("### errors ### "+results.getMessages());
}
}

public KieSession getKieSession() {
return pool.newKieSession();
}

------------------------Client-----------------------
@Service
public class DroolsRuleExecutorService  {

@Autowired
private DroolsBeanFactory droolsBeanFactory;

public RuleExecutionOutcome executeTreeNodeRule(Integer idRule, Practice practice) {
KieSession kieSession = droolsBeanFactory.getKieSession();
RuleExecutionOutcome reo = new RuleExecutionOutcome();
kieSession.insert(practice);
kieSession.setGlobal("ruleExecutionOutcome", reo);
kieSession.fireAllRules(new RuleNameEndsWithAgendaFilter("R" + String.valueOf(idRule)));
kieSession.dispose();
return reo;
}


----------------Example of rules----------------------------
dialect  "mvel"  

rule "1_R4" 
activation-group "rule_4"     
when         
Practice(inputDate != null && ChronoUnit.DAYS.between(inputDate, runDate) <= 180)     
then        
ruleExecutionOutcome.setResult("INSIDE"); 
end  

rule "2_R4" 
activation-group "rule_4"     
when         
eval(true)     
then         
ruleExecutionOutcome.setResult("OUTSIDE"); 
end
-------------------------------

Now imagine that the days between input date and run date are 90.
If the Engine use the first completely new session the output of rule is "INSIDE", after some attempts when the Engine reuses the session and the output became " OUTSIDE ". This is reason why I have thought that the activation group doesn’t work. Another assumption can be related to eval (true), I don't know if for this particular condition the Engine save internally some information that are reused for the next executions.
Consider the rules just an example I know that it can be written better to avoid to use eval(true), but in some our cases we need to use it.

Thank you

Michele 

Luca Molteni

unread,
Aug 18, 2021, 3:28:40 AM8/18/21
to drools...@googlegroups.com


> On 17 Aug 2021, at 16:22, michele <michelepa...@gmail.com> wrote:
>
> Hi Luca, I try to explain the implementation here, if necessary I can try to create unit test:
>


Thanks Michele, it definitely looks like a bug.

Can you provide a reproducer with a unit test possibly without Spring?

If you want you can file a Jira on https://issues.redhat.com as well, otherwise I’ll do it for you

Thank you

Luca

Reply all
Reply to author
Forward
0 new messages