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