[rules-users] Confusing behavior for StatefulKnowledgeSession.fireAllRules() with negated conditions.
bill simms
sitrious at gmail.com
Tue Sep 8 17:11:00 EDT 2009
Thanks Edson. That helps tremendously.
2009/9/8 Edson Tirelli <tirelli at post.com>
>
> Section 2.5.2.2 of the documentation:
>
>
> http://downloads.jboss.com/drools/docs/5.0.1.26597.FINAL/drools-fusion/html_single/index.html#d0e1086
>
> The documentation does not goes down in all the details, but negated
> patterns will cause the rule to wait and asynchronously fire (like when
> using the duration attribute) when the matching pattern is not readily
> available.
>
> For deterministic unit testing you need to use a pseudo clock, instead
> of the default realtime clock.
>
> []s
> Edson
>
> 2009/9/8 bill simms <sitrious at gmail.com>
>
>> Hello again,
>>
>> Recently while continuing to work on a complex event processing project I
>> have encountered strange,
>> but interesting, situations where the fireAllRules() method of a
>> StatefulKnowledgeSession appears to
>> return before actually emptying the activations on the agenda. I was
>> under the impression that this
>> method only returns after all activations, including subsequent
>> activations, have been completed and
>> removed from the agenda. If I'm incorrect then feel free to disregard the
>> rest of this message.
>>
>> [Drools v 5.0.1, JUnit 4.0, Spring 2.5.6]
>>
>> The behavior I have noticed begins when working with a rule such as "Find
>> Missing Input Events"
>> (in file test.drl):
>> ------------------------------------------------------------------------
>> package org.drools.test
>>
>> import org.drools.test.*
>>
>> declare Event
>> @role( event )
>> @timestamp( beginning )
>> @duration( length )
>> @expires( 1h )
>> end
>>
>> declare Fault
>> @role( event )
>> @timestamp( beginning )
>> @duration( length )
>> @expires( 1h )
>> end
>>
>> query "getFaults"
>> $fault: Fault() from entry-point "faults"
>> end
>>
>> rule "Find Missing Input Events"
>> when
>> $a: Event()
>> from entry-point "input"
>> $b: Event( this after $a)
>> from entry-point "input"
>> not (Event( (this after $a || this metby $a), (this before $b ||
>> this meets $b))
>> from entry-point "input")
>> not (Fault(this metby $a, this meets $b)
>> from entry-point "faults")
>> then
>> entryPoints["faults"].insert(new Fault($a, $b));
>> end
>>
>> rule "Print Faults"
>>
>> when
>> $f: Fault() from entry-point "faults"
>> then
>> System.out.println($f);
>> end
>> ------------------------------------------------------------------------
>>
>> The purpose of this rule is to detect when one or more events are missing
>> in an event sequence. The
>> events in question are supposed to continue from one to the next without
>> any time in-between. If this
>> rule does discover a gap/absence between two events a Fault is created for
>> further processing. (*Note
>> that the Event and Fault classes that I used only contain two fields,
>> beginning and length, to be used as
>> the time-stamp and duration respectively.) I noticed the unexpected
>> behavior shortly after creating this
>> unit test:
>>
>> ------------------------------------------------------------------------
>> public class FireAllRulesTest {
>>
>> KnowledgeBase knowledgeBase;
>>
>> StatefulKnowledgeSession session;
>>
>> /**
>> * @throws java.lang.Exception
>> */
>> @Before
>> public void setUp() throws Exception {
>> KnowledgeBuilder builder =
>> KnowledgeBuilderFactory.newKnowledgeBuilder();
>>
>> builder.add(ResourceFactory.newFileResource("target/test-classes/test.drl"),
>> ResourceType.DRL);
>>
>> if(builder.hasErrors()){
>> throw new RuntimeException(builder.getErrors().toString());
>> }
>> KnowledgeBaseConfiguration configuration =
>> KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
>> configuration.setOption(EventProcessingOption.STREAM);
>>
>> knowledgeBase =
>> KnowledgeBaseFactory.newKnowledgeBase(configuration);
>>
>> knowledgeBase.addKnowledgePackages(builder.getKnowledgePackages());
>>
>> session = knowledgeBase.newStatefulKnowledgeSession();
>> WorkingMemoryConsoleLogger logger = new
>> WorkingMemoryConsoleLogger(session);
>> }
>>
>> @Test
>> public void testAbsence(){
>> System.out.println("Running...");
>> //Record the rules that have fired.
>> ActivationTrackingEventListener listener = new
>> ActivationTrackingEventListener();
>> session.addEventListener(listener);
>>
>> //Start at 0, go to 100.
>> Event first = new Event(0,100);
>>
>> //Start at 1000, go to 1100. Absence of 900.
>> Event second = new Event(1000, 100);
>>
>> //Start at 1100, go to 1200. No absence.
>> Event third = new Event(1100, 100);
>>
>> //Start at 1200, go to 1300. No absence.
>> Event fourth = new Event(1200, 100);
>>
>> //Start at 2000, go to 2100. Absence of 700.
>> Event fifth = new Event(2000, 100);
>>
>> WorkingMemoryEntryPoint ingest =
>> session.getWorkingMemoryEntryPoint("input");
>> ingest.insert(first);
>> ingest.insert(second);
>> ingest.insert(third);
>> ingest.insert(fourth);
>> ingest.insert(fifth);
>>
>> System.out.println("All events have been inserted.");
>>
>> session.fireAllRules();
>>
>> System.out.println("Rules have finished firing.");
>>
>> //Expect that "Find Missing Input Events" has fired and that there
>> are two faults as a result.
>> assertTrue(listener.hasRuleFired("Find Missing Input Events"));
>> assertEquals(2,faultCount());
>>
>> System.out.println("Test completed.");
>> }
>>
>> public int faultCount(){
>> QueryResults results = session.getQueryResults("getFaults");
>> return results.size();
>> }
>>
>> }
>> ------------------------------------------------------------------------
>>
>> The typical result of this test is a failure about 90% of the time.
>> Strangely, the other 10% of the time this exact
>> same test is run it will pass, without any modifications. Equally
>> interesting is the output of the WorkingMemoryLogger:
>>
>> ------------------------------------------------------------------------
>> Running...
>> OBJECT ASSERTED value:org.drools.test.Event at 1b994de factId: 1
>> BEFORE ACTIVATION FIRED rule:Find Missing Input Events activationId:Find
>> Missing Input Events [2, 1, 0]
>> declarations: $b=org.drools.test.Event at 2803d5(2);
>> $a=org.drools.test.Event at 1b994de(1)
>> ACTIVATION CREATED rule:Find Missing Input Events activationId:Find
>> Missing Input Events [2, 1, 0]
>> declarations: $b=org.drools.test.Event at 2803d5(2);
>> $a=org.drools.test.Event at 1b994de(1)
>> OBJECT ASSERTED value:org.drools.test.Event at 2803d5 factId: 2
>> OBJECT ASSERTED value:org.drools.test.Event at 1b32627 factId: 3
>> OBJECT ASSERTED value:org.drools.test.Event at ad157f factId: 4
>> ACTIVATION CREATED rule:Find Missing Input Events activationId:Find
>> Missing Input Events [5, 4, 0]
>> declarations: $b=org.drools.test.Event at 1bfa3d3(5);
>> $a=org.drools.test.Event at ad157f(4)
>> OBJECT ASSERTED value:org.drools.test.Event at 1bfa3d3 factId: 5
>> All events have been inserted.
>> ***Rules have finished firing.
>> ACTIVATION CREATED rule:Print Faults activationId:Print Faults [6, 0]
>> declarations: $f=org.drools.test.Fault at 159780d(6)
>> OBJECT ASSERTED value:org.drools.test.Fault at 159780d factId: 6
>> AFTER ACTIVATION FIRED rule:Find Missing Input Events activationId:Find
>> Missing Input Events [2, 1, 0]
>> declarations: $b=org.drools.test.Event at 2803d5(2);
>> $a=org.drools.test.Event at 1b994de(1)
>> BEFORE ACTIVATION FIRED rule:Print Faults activationId:Print Faults [6, 0]
>> declarations: $f=org.drools.test.Fault at 159780d(6)
>> org.drools.test.Fault at 159780d
>> AFTER ACTIVATION FIRED rule:Print Faults activationId:Print Faults [6, 0]
>> declarations: $f=org.drools.test.Fault at 159780d(6)
>> BEFORE ACTIVATION FIRED rule:Find Missing Input Events activationId:Find
>> Missing Input Events [5, 4, 0]
>> declarations: $b=org.drools.test.Event at 1bfa3d3(5);
>> $a=org.drools.test.Event at ad157f(4)
>> ACTIVATION CREATED rule:Print Faults activationId:Print Faults [7, 0]
>> declarations: $f=org.drools.test.Fault at c26b16(7)
>> OBJECT ASSERTED value:org.drools.test.Fault at c26b16 factId: 7
>> AFTER ACTIVATION FIRED rule:Find Missing Input Events activationId:Find
>> Missing Input Events [5, 4, 0]
>> declarations: $b=org.drools.test.Event at 1bfa3d3(5);
>> $a=org.drools.test.Event at ad157f(4)
>> BEFORE ACTIVATION FIRED rule:Print Faults activationId:Print Faults [7, 0]
>> declarations: $f=org.drools.test.Fault at c26b16(7)
>> org.drools.test.Fault at c26b16
>> AFTER ACTIVATION FIRED rule:Print Faults activationId:Print Faults [7, 0]
>> declarations: $f=org.drools.test.Fault at c26b16(7)
>> ------------------------------------------------------------------------
>>
>> It seems that the rule is indeed firing correctly, but that it is doing so
>> only after returning from fireAllRules method.
>> I have marked line that follows fireAllRules() with *** above. So the
>> rule fires, but the test fails because the firing
>> takes place after the junit assertions are checked.
>>
>> But that's not all, it gets more interesting. Looking back at the rule
>> file, when you comment out the last condition:
>>
>> not (Fault(this metby $a, this meets $b)
>> from entry-point "faults")
>>
>> The problem with the unit test disappears. After much thought I'm still
>> not sure why this is, but the last condition is
>> critical to avoid creating redundant Faults (Because a lot of the Events
>> are redundant as well. It just comes with the
>> problem being solved). The problem also disappears if you put a
>> Thread.sleep(1000) after firing the rules, which is
>> why I suspect a timing issue between the rules firing and the unit test
>> assertions being evaluated. This could explain
>> why the test sometimes works, and sometimes doesn't.
>>
>> I'm hopeful that someone will understand why this is happening, and point
>> how how to prevent it. Thank you in advance.
>>
>> Bill
>>
>>
>> _______________________________________________
>> rules-users mailing list
>> rules-users at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/rules-users
>>
>>
>
>
> --
> Edson Tirelli
> JBoss Drools Core Development
> JBoss by Red Hat @ www.jboss.com
>
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20090908/4e5eb953/attachment.html
More information about the rules-users
mailing list