Drools, похоже, дает неправильные результаты, когда несколько процессов выполняются параллельно, и в каждом процессе каждый раз создается и обрабатывается новый объект KieBase
.
Пробуется с версиями: 6.5.0.Final
, 7.32.0.Final
Подробности:
Я выполнил 120 задач параллельно (используя 7 потоков). Из этих 120 задач слюни дали правильный результат для 108 задач, но выполнили неправильное правило для 12 задач (количество таких неудачных задач варьируется при каждом запуске).
Позвольте мне выложить код и вывести здесь:
public class TempClass {
public List<String> droolLogging = new ArrayList<>();
}
public void execute(){
Map<String, List<String>> failedTasks = new ConcurrentHashMap<>(); // to see which tasks were incorrectly executed
// Run 120 tasks in parallel using x threads (x depends upon no of processor)
IntStream.range(1, 120).parallel()
.forEach(taskCounter -> {
String uniqueId = "Task-"+taskCounter;
TempClass classObj = new TempClass();
String ruleString = "package com.sample" + taskCounter + "\n" +
"import com.TempClass\n" +
"\n" +\
"rule \"droolLogging"+taskCounter+"\"\n" +
"\t when \n" +
"\t\t obj: TempClass(true)\n" +
"\t then \n" +
"\t\t obj.droolLogging.add(\"RuleOf-"+uniqueId+"\");\n" +
"\t end\n";
// Above ruleString contains 1 rule and it is always executed.
// After execution, it will add an entry in array list 'droolLogging'
// of class 'TempClass'. In this entry, we are storing task counter
// to see rule of which task is executed.
//following line of code seems to be the culprit as this is somehow returning incorrect KieBase sometime.
KieBase kbase = new KieHelper()
.addContent(ruleString, ResourceType.DRL)
.build();
/*
//Same issue occurs even if I create different file with different name instead of using KieHelper.
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem();
String inMemoryDrlFileName = "src/main/resources/inmemoryrules-" + taskCounter + ".drl";
kfs.write(inMemoryDrlFileName, ruleString);
KieBuilder kieBuilder = ks.newKieBuilder(kfs).buildAll();
KieContainer kContainer = ks.newKieContainer(kieBuilder.getKieModule().getReleaseId());
KieBaseConfiguration kbconf = ks.newKieBaseConfiguration();
KieBase kbase = kContainer.newKieBase(kbconf);
*/
StatelessKieSession kieSession = kbase.newStatelessKieSession();
kieSession.execute(classObj);
System.out.println("(" + Thread.currentThread().getName() + ") " +
uniqueId + "_" + classObj.droolLogging );
//Important:
// To see if correct rule is executed, task no. printed by variable 'droolLogging'
// should match with uniqueId
if(classObj.droolLogging == null || classObj.droolLogging.size() != 1 ||
!classObj.droolLogging.get(0).endsWith(uniqueId)) {
failedTasks.put("" + taskCounter, classObj.droolLogging);
}
});
logger.info("Failed:\n {}", failedTasks);
}
OUTPUT:
(ForkJoinPool.commonPool-worker-1) Task-37_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-6) Task-8_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-3) Task-18_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-2) Task-108_[RuleOf-Task-4]
(main) Task-78_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-7) Task-52_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-4) Task-97_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-5) Task-4_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-3) Task-19_[RuleOf-Task-19]
(ForkJoinPool.commonPool-worker-5) Task-5_[RuleOf-Task-5]
(ForkJoinPool.commonPool-worker-2) Task-109_[RuleOf-Task-109]
(ForkJoinPool.commonPool-worker-7) Task-53_[RuleOf-Task-53]
(ForkJoinPool.commonPool-worker-1) Task-38_[RuleOf-Task-38]
(ForkJoinPool.commonPool-worker-4) Task-98_[RuleOf-Task-98]
.... more
Failed (12):
{88=[RuleOf-Task-77], 78=[RuleOf-Task-4], 68=[RuleOf-Task-60], 37=[RuleOf-Task-4], 15=[RuleOf-Task-1], 18=[RuleOf-Task-4], 7=[RuleOf-Task-11], 8=[RuleOf-Task-4], 108=[RuleOf-Task-4], 71=[RuleOf-Task-76], 52=[RuleOf-Task-4], 97=[RuleOf-Task-4]}
This shows:
- Rule of task 77 was executed in task 88
- Rule of task 4 was executed in task 78
- Rule of task 60 was executed in task 68
- ....
This is wrong. For correct results, in each process, Rule of task X should be executed in task X only.
Есть идеи, что может быть причиной этого?
Обновление: Приведенный выше код предназначен только для тестирования, чтобы увидеть, как генерация и выполнение KieBase
будут вести себя в многопоточной среде. Фактический вариант использования выглядит следующим образом:
Вариант использования:
У нас есть набор правил, относящихся к категории. Для каждой категории должен быть выполнен определенный набор правил.
Example:
for category 1 , I need to execute rule101, rule102, rule103
for category 2 , I need to execute rule201, rule202, rule203
....
Note: During evaluation, rules of category X should NOT interfere with Rules of category Y, i.e., they should be run independently.
Поскольку нет. категорий огромные, мы строим KieBases
(для каждой категории) параллельно и храним его в течение x минут. Через x минут мы проверяем, были ли изменены правила для какой-либо категории, если изменилось, KieBase
снова скомпилируется для этих категорий (что снова будет параллельно).
Кроме того, новые категории могут быть добавлены при запуске время. Таким образом, для новых добавленных категорий также соблюдается вышеуказанная процедура.
category1 -> KieBase1 (compiled rules: rule101, rule102, rule103)
category2 -> KieBase2 (compiled rules: rule201, rule202, rule203)
category3 -> KieBase3
Note: As already mentioned above, execution of KieBase X should NOT interfere with execution of KieBase Y as KieBases are created category wise and for each category, only particular set of rules should be executed.