Business rule execute only once on jbpm process - drools

I execute a business rule from a process on Jbpm, the rule is simple:
package com.test.flow;
rule "sample"
ruleflow-group "test"
when
then
System.out.println("Hello World");
end
But, I don't no why, this rule execute only once, for instance, I run a new instance of the process and in the jbpm console print "Hello World", but, when I run a second instance of the process doesn print anymore "Hello World", some one can you help me? or tellme why does this happen?
Screen Jbpm console

For this kind of "hello-world" rule, using ruleflow-group is most likely just causing confusion. Do you control when this group is activated? How? - Omitting this rule attribute is indicated.
A rule with an empty left-hand-side will execute only once in a session (as Esteban pointed out).
If you want a rule that fires once for each inserted fact, use
rule "new fact"
when
Object()
then
System.out.println( "new fact inserted" );
end

Related

Why does Drools re-evaluate and re-trigger rule actions after a persistent session is reloaded?

I have a simple rule like the one below:
package rules
dialect "mvel"
declare MyEvent
#role( event )
#expires( 2d )
id String
value: Double
end
rule "My Rule"
when
MyEvent($value : value)
then
System.out.println("My event with value: " + $value);
end
I create a persistent session and call fireAllRules() on it. Then, I insert a MyEvent fact, and as expected the rule is evaluated, matched and the action is executed. If I call fireAllRules() again the rule is not matched, as expected because it has already matched for the same fact. At this point everything is fine.
Then I kill the JVM and run the app again. At startup the app loads the session like this:
kieSession = kieServices.getStoreServices().loadKieSession(KIE_SESSION_ID, kieBase, kieSessionConfiguration, kieEnvironment);
The session gets loaded successfully, and then fireAllRules() is called again. Since the rule has already matched for the inserted event, I am expecting that it does not match again. However I can see the message in the rule action is printed again. Why does Drools match the rule for the same eventagaian? To me it looks like the session state is not properly saved to database. I mean, the event is saved, but Drools can not recogonize that it has already matched the rule. When I load a persistent session I expect to recover exactly the same state that the session had in the previous running instance. Is my assumption wrong? or Am I doing something wrong for the expected behaviour?
Running:
JavaSE 11
SpringBoot 2.3
Drools 7.53.0

JBPM work items in guided decision table only executed once?

I am designing a guided decision table to execute some work items which are simply printing out some texts in executeWorkItem function.
In the workbench settings, I have added the work item handlers into a stateful session. Also I have defined them in a wid file.
The rules in the guided decision table is quite straightforward. It is as following in source view
//from row number: 1
rule "Row 1 dt1"
dialect "mvel"
when
then
org.drools.core.process.instance.WorkItemManager wim = (org.drools.core.process.instance.WorkItemManager) drools.getWorkingMemory().getWorkItemManager();
org.drools.core.process.instance.impl.WorkItemImpl wiQianhaiAddrWorkItemHandler = new org.drools.core.process.instance.impl.WorkItemImpl();
wiQianhaiAddrWorkItemHandler.setName( "QianhaiAddrWorkItemHandler" );
wim.internalExecuteWorkItem( wiQianhaiAddrWorkItemHandler );
end
No conditional checking just because I want to fire it every time there is a request sent to the KIE server.
This is the request fired to KIE server
URL:http://localhost:8080/kie-server/services/rest/server/containers/instances/poc2_1.0.1
body:
{"commands": [
{
"fire-all-rules": {}
}
]}
I can see the work item was executed when first time the request fired to KIE server. However, it doesn't run anymore since the second time because I couldn't see any printing in console.
The response from KIE server is always correct as following
{
"type" : "SUCCESS",
"msg" : "Container poc2_1.0.1 successfully called.",
"result" : {
"execution-results" : {
"results" : [ ],
"facts" : [ ]
}
}
}
May I know how to execute the work item per my "fire-all-rules" command sent? Or is it a default behavior in JBPM ?
Let's start by saying that even if you are using a WorkItemManager your problem is entirely related to Drools.
In Drools, a rule without conditions is only going to be executed once per session the first time you or somebody calls fireAllRules(). In your case, because your requests are reusing the same stateful session, your rule will be executed once.
The first approach would be to use a stateless session if possible. If that's not possible, you may need to explicitly tell Drools when a new request is processed by sending a fact along with the request and to adding it to the condition of your rule. You can later on remove these facts if you don't need them in your session:
rule "Row 1 dt1"
dialect "mvel"
when
Request()
then
org.drools.core.process.instance.WorkItemManager wim = (org.drools.core.process.instance.WorkItemManager) drools.getWorkingMemory().getWorkItemManager();
org.drools.core.process.instance.impl.WorkItemImpl wiQianhaiAddrWorkItemHandler = new org.drools.core.process.instance.impl.WorkItemImpl();
wiQianhaiAddrWorkItemHandler.setName( "QianhaiAddrWorkItemHandler" );
wim.internalExecuteWorkItem( wiQianhaiAddrWorkItemHandler );
end
rule "Cleanup Request"
salience -10
when
$r: Request()
then
delete($r);
end
Hope it helps,

how to add value to duration attribute in drools

Whenever i write duration(0s), it works but as soon as i change it to duration(1s) or duration(5s), the rule doesn't fire...
This is the rule which i want to fire.
rule "ContainsChecking"
agenda-group "town4"
duration(0s)
when
Town(owner matches "[N || n][a-z]+")
then
System.out.println("Rule Fired ContainsChecking");
end
do we need to import something for duration attribute to work, because i m not getting it anywhere. Thanks in advance.
You need to run the session using
kieSession.fireUntilHalt();
If you just use fireAllRules, the agenda is empty and the call terminates.
This is a CEP feature and need not and should not be used in a simple production rule environment.

Is there a way to chain two arbitrary specs2 tests (in Scala)?

Every now and then I run into a situation where I need to make absolutely sure that one test executes (successfully) before another one.
For example:
"The SecurityManager" should {
"make sure an administrative user exists" in new WithApplication with GPAuthenticationTestUtility {
checkPrerequisiteAccounts(prerequisiteAccounts)
}
"get an account id from a token" in new WithApplication with GPAuthenticationTestUtility {
val token = authenticate(prerequisiteAccounts.head)
token.isSuccess must beTrue
myId = GPSecurityController.getAccountId(token.get)
myId != None must beTrue
myId.get.toInt > 0 must beTrue
}
The first test will create the admin user if it doesn't exist. The second test uses that account to perform a test.
I am aware I can do a Before/After treatment in specs2 (though I've never done one). But I really don't want checkPrerequisiteAccounts to run before every test, just before that first test executes... sort of a "before you start doing anything at all, do this one thing..."
Anyone know if there is a way to tag a particular test as "do first" or "do before anything else?"
You can just add a "Step" in between tests to enforce some sequentiality:
"make sure an administrative user exists" in ok
step("admin is created".pp)
"get an account id from a token" in ok
You can also add sequential to your spec like, to sequential execution of tests.
class MySpec extends mutable.Specification {
sequential
// rest follows
behaviour one
behaviour two
}

drools 5: NullPointerException when sharing KnowledgeBase across processes

We have a cluster of jboss instances running drools. We generate the KnowledgeBase on one instance, then store it in a database; the other instances can then load it from the database instead of generating it themselves.
This has worked well for some time using drools 4, but we recently upgraded to drools 5.3.0 BRMS and the pattern no longer works. The KnowledgeBase works fine within the app instance in which it was generated, but it fails everywhere else with the following exception. Note that this exception happens upon inserting a fact into working memory.
All instances of the app are identical, they run in the same jvm, etc. The 'other' instance does not need to be on a different physical machine -- it can be on the same hardware, and the failure still occurs.
What is it about a KnowledgeBase that makes it fail in a different jvm instance from the one in which it was generated? Is there some way to avoid this problem? Thanks.
This is the drl in which the failure seems to happen. I've done some debugging through the mvel code, but I'm not familiar with it and I haven't figured out what's going on. I think the expression on which the failure occurs is the 'this.fact.requirementId'.
rule "Find OutOfOrder PredicateSolutions for new LeafPredicateSolution in rule [Become Application Expired : 147]"
ruleflow-group "RuleGroup[Become Application Expired:147]"
agenda-group "leaf"
no-loop
salience -1001
when
EngineDates($rewindToDate: engineEffectiveDate);
lps:LeafPredicateSolution(
ruleId==147,
parent==null,
$candidateId:candidateId,
defunct==false,
fact:fact,
effectiveDate == $rewindToDate,
$programId:programId,
eval(!fact.getReused())); // only solutions created for the fact we're running on can trigger OoO
oops : ArrayList() from accumulate(
PredicateSolution(
$sol:this,
candidateId==$candidateId,
effectiveDate > $rewindToDate,
defunct==false,
programId==$programId,
parent!=null,
solutionType!=SolutionType.RETIRED,
eval(($sol instanceof LeafPredicateSolution) || ($sol instanceof NonCalcProgramSolutionChild))
),
init(ArrayList items = new ArrayList();),
action(items.add($sol);),
reverse(items.remove($sol);),
result(items));
// Find ProgramPredicateSolutions in other programs that refer to this program.
// These need to be rewound.
oopps:ArrayList() from collect(
ProgramPredicateSolution(
this.fact.requirementId == $programId,
candidateId==$candidateId,
effectiveDate > $rewindToDate,
defunct==false,
parent!=null,
solutionType!=SolutionType.RETIRED));
eval((oops.size() > 0) || (oopps.size() > 0));
eval(predicateSolutionFactory.oopEnabled());//Don't run oop if it is disabled (TimeMachine, Whatif)
then
predicateSolutionFactory.addToOutOfOrder(lps, oops, oopps, new Long(65));
end
Stack trace:
java.lang.NullPointerException
at org.mvel2.MVEL.executeExpression(MVEL.java:954)
at org.drools.base.extractors.MVELClassFieldReader.getValue(MVELClassFieldReader.java:100)
at org.drools.base.extractors.BaseObjectClassFieldReader.getHashCode(BaseObjectClassFieldReader.java:196)
at org.drools.core.util.AbstractHashTable$DoubleCompositeIndex.hashCodeOf(AbstractHashTable.java:616)
at org.drools.core.util.RightTupleIndexHashTable.getOrCreate(RightTupleIndexHashTable.java:451)
at org.drools.core.util.RightTupleIndexHashTable.add(RightTupleIndexHashTable.java:332)
at org.drools.reteoo.AccumulateNode.assertObject(AccumulateNode.java:263)
at org.drools.reteoo.CompositeObjectSinkAdapter.doPropagateAssertObject(CompositeObjectSinkAdapter.java:458)
at org.drools.reteoo.CompositeObjectSinkAdapter.propagateAssertObject(CompositeObjectSinkAdapter.java:386)
at org.drools.reteoo.AlphaNode.assertObject(AlphaNode.java:135)
at org.drools.reteoo.SingleObjectSinkAdapter.propagateAssertObject(SingleObjectSinkAdapter.java:59)
at org.drools.reteoo.AlphaNode.assertObject(AlphaNode.java:135)
at org.drools.reteoo.SingleObjectSinkAdapter.propagateAssertObject(SingleObjectSinkAdapter.java:59)
at org.drools.reteoo.AlphaNode.assertObject(AlphaNode.java:135)
at org.drools.reteoo.CompositeObjectSinkAdapter.doPropagateAssertObject(CompositeObjectSinkAdapter.java:458)
at org.drools.reteoo.CompositeObjectSinkAdapter.propagateAssertObject(CompositeObjectSinkAdapter.java:376)
at org.drools.reteoo.ObjectTypeNode.assertObject(ObjectTypeNode.java:214)
at org.drools.reteoo.EntryPointNode.assertObject(EntryPointNode.java:244)
at org.drools.common.NamedEntryPoint.insert(NamedEntryPoint.java:337)
at org.drools.common.NamedEntryPoint.insert(NamedEntryPoint.java:298)
at org.drools.common.AbstractWorkingMemory.insert(AbstractWorkingMemory.java:887)
at org.drools.common.AbstractWorkingMemory.insert(AbstractWorkingMemory.java:846)
at org.drools.impl.StatefulKnowledgeSessionImpl.insert(StatefulKnowledgeSessionImpl.java:267)