Skip to content

Instantly share code, notes, and snippets.

@dacr
Last active June 24, 2023 16:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dacr/12dbb61d923b38a4694379e6be8d0086 to your computer and use it in GitHub Desktop.
Save dacr/12dbb61d923b38a4694379e6be8d0086 to your computer and use it in GitHub Desktop.
Drools understanding events base knowledge base / published by https://github.com/dacr/code-examples-manager #d4fe0ba1-43aa-433a-b03c-9806cc5b1081/c42bbf4d7a4520e49844f701f835147c8a3532ba
// summary : Drools understanding events base knowledge base
// keywords : scala, drools, mvel, scalatest, ai, knowledgebase, events, @testable
// publish : gist
// authors : David Crosson
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2)
// id : d4fe0ba1-43aa-433a-b03c-9806cc5b1081
// created-on : 2019-10-06T21:12:41+02:00
// managed-by : https://github.com/dacr/code-examples-manager
// run-with : scala-cli $file
// ---------------------
//> using scala "3.3.0"
//> using dep "fr.janalyse::drools-scripting:1.1.0"
//> using dep "org.scalatest::scalatest:3.2.16"
//> using objectWrapper
// ---------------------
import java.time.Instant
import fr.janalyse.droolscripting._
import org.scalatest._
import flatspec._
import matchers._
import OptionValues._
class UnderstandingEventsRules extends AnyFlatSpec with should.Matchers {
override def suiteName: String = "UnderstandingEventsRules"
// ======================================================================
"DROOLS" should "be able to delay rule execution" in {
val drl =
"""package test //#EEX1
|rule "init"
|duration 10000 // 10 seconds
|when then insert("OK"); end
|""".stripMargin
val engine = DroolsEngine(drl)
engine.fireAllRules()
engine.strings should have size (0)
engine.timeShiftInSeconds(12)
engine.fireAllRules()
engine.strings should have size (1)
}
// ======================================================================
it should "be able to define a point-in-time event" in {
val drl =
"""package test //#EEX2
|declare CpuPeak @role(event)
| value:double
|end
|rule "init" when then insert(new CpuPeak(95.0)); end
|//-----------------
|rule "show event" when $peak:CpuPeak() then
| insert("CPU peak reached :"+$peak.toString());
|end
|""".stripMargin
val engine = DroolsEngine(drl)
engine.fireAllRules()
info("In that case the timestamp is automatically inserted, initialized with current time")
val result = engine.strings.headOption.value
result.toString should startWith regex "CPU peak reached"
}
// ======================================================================
it should "be able to define an interval-based event" in {
val drl =
"""package test //#EEX3
|declare Processed @role(event) @duration(duration)
| name:String
| duration:long
|end
|rule "init" when then insert(new Processed("Cooking", 500)); end
|//-----------------
|rule "show event" when Processed($name:name, $duration:duration) then
| insert($name+" has been processed in"+$duration);
|end
|""".stripMargin
val engine = DroolsEngine(drl)
engine.fireAllRules()
info("In that case the timestamp is also automatically inserted, initialized with current time")
val result = engine.strings.headOption.value
result.toString should include regex ".* has been processed"
val processed = engine.getModelFirstInstance("test.Processed").value
engine
.getModelInstanceAttribute(processed, "duration")
.collect { case l: java.lang.Long => l }
.value shouldBe 500
}
// ======================================================================
it should "be possible for a point-in-time event to expire" in {
val drl =
"""package test //#EEX4
|declare SomethingHappened @role(event) @expires(5s)
| message:String
|end
|rule "init" when then insert(new SomethingHappened("Bad stuff")); end
|""".stripMargin
val engine = DroolsEngine(drl)
engine.fireAllRules()
engine.getModelInstances("test.SomethingHappened").toList should have size (1)
engine.timeShiftInSeconds(4) // t+4s
engine.fireAllRules()
engine.getModelInstances("test.SomethingHappened").toList should have size (1)
engine.timeShiftInSeconds(2) // t+6s
engine.fireAllRules()
engine.getModelInstances("test.SomethingHappened").toList should have size (0)
info("event expire is a convenient way to keep memory usage under control")
}
// ======================================================================
it should "be possible for an interval-based event to expire" in {
val drl =
"""package test //#EEX5
|declare SomethingHappened @role(event) @expires(5s) @duration(duration)
| message:String
| duration:long
|end
|rule "init" when then insert(new SomethingHappened("Bad stuff",10000)); end
|""".stripMargin
val engine = DroolsEngine(drl)
engine.fireAllRules()
engine.getModelInstances("test.SomethingHappened").toList should have size (1)
engine.timeShiftInSeconds(4) // t+4s
engine.fireAllRules()
engine.getModelInstances("test.SomethingHappened").toList should have size (1)
engine.timeShiftInSeconds(2) // t+6s
engine.fireAllRules()
engine.getModelInstances("test.SomethingHappened").toList should have size (1)
engine.timeShiftInSeconds(8) // t+14s
engine.fireAllRules()
engine.getModelInstances("test.SomethingHappened").toList should have size (1)
engine.timeShiftInSeconds(2) // t+16s
engine.fireAllRules()
engine.getModelInstances("test.SomethingHappened").toList should have size (0)
info("An interval-based event expires at (startTimestamp + duration + expires ) > currentClock !")
info("which corresponds to (endTimestamp + expires) > currentClock !")
}
// ======================================================================
it should "be able to define an event using a custom date" in {
val drl =
"""package test //#EEX6
|declare CpuPeak @role(event) @timestamp(timestamp)
| timestamp: java.util.Date
| value:double
|end
|//-----------------
|rule "show event" when $peak:CpuPeak() then
| insert("CPU peak reached :"+$peak.toString());
|end
|""".stripMargin
val engine = DroolsEngine(drl)
engine.insertJson("""{"timestamp":"2019-01-01T14:00:00Z", "value":95.0}""", "test.CpuPeak")
engine.fireAllRules()
val result = engine.strings.headOption.value
result.toString should startWith regex "CPU peak reached"
}
// ======================================================================
it should "be able to search for two consecutive point-in-time events" in {
val drl =
"""package test //#EEX7
|declare CpuPeak @role(event) @timestamp(timestamp)
| timestamp: java.util.Date
| value:double
|end
|//-----------------
|rule "show event" when
| $peak1:CpuPeak()
|// $peak2:CpuPeak(this after $peak1)
| $peak2:CpuPeak($peak1 before this)
|then
| insert("CPU peak reached :"+$peak1.toString());
|end
|""".stripMargin
val engine = DroolsEngine(drl)
engine.insertJson("""{"timestamp":"2019-01-01T14:00:00Z", "value":95.0}""", "test.CpuPeak")
engine.insertJson("""{"timestamp":"2019-01-01T15:00:00Z", "value":95.0}""", "test.CpuPeak")
engine.fireAllRules()
val result = engine.strings.headOption.value
result.toString should startWith regex "CPU peak reached"
}
// ======================================================================
it should "be able to search for two consecutive near-by point-in-time events" in {
val drl =
"""package test //#EEX8
|declare CpuPeak @role(event) @timestamp(timestamp)
| timestamp: java.util.Date
| value:double
|end
|//-----------------
|rule "show event" when
| $peak1:CpuPeak($value1:value, value > 90)
| $peak2:CpuPeak($value2:value,value > 90, this after[0,15m] $peak1, this != $peak1 )
|then
| insert("Too many CPU peaks : "+$value1+" "+$value2);
|end
|""".stripMargin
val engine = DroolsEngine(drl)
engine.insertJson("""{"timestamp":"2019-01-01T14:00:00Z", "value":95.0}""", "test.CpuPeak")
engine.insertJson("""{"timestamp":"2019-01-01T15:00:00Z", "value":96.0}""", "test.CpuPeak")
engine.insertJson("""{"timestamp":"2019-01-01T15:10:00Z", "value":97.0}""", "test.CpuPeak")
engine.fireAllRules()
val results = engine.strings
results should have size (1)
results.headOption.value shouldBe "Too many CPU peaks : 96.0 97.0"
}
// ======================================================================
it should "be able to search for two consecutive near-by point-in-time events using epochs timestamp" in {
val drl =
"""package test //#EEX8B
|declare CpuPeak @role(event) @timestamp(timestamp)
| timestamp: long
| value:double
|end
|//-----------------
|rule "show event" when
| $peak1:CpuPeak($value1:value, value > 90)
| $peak2:CpuPeak($value2:value,value > 90, this after[0,15m] $peak1, this != $peak1 )
|then
| insert("Too many CPU peaks : "+$value1+" "+$value2);
|end
|""".stripMargin
val engine = DroolsEngine(drl)
def epochOf(timestamp: String): Long = Instant.parse(timestamp).toEpochMilli
engine.insertJson(s"""{"timestamp":${epochOf("2019-01-01T14:00:00Z")}, "value":95.0}""", "test.CpuPeak")
engine.insertJson(s"""{"timestamp":${epochOf("2019-01-01T15:00:00Z")}, "value":96.0}""", "test.CpuPeak")
engine.insertJson(s"""{"timestamp":${epochOf("2019-01-01T15:10:00Z")}, "value":97.0}""", "test.CpuPeak")
engine.fireAllRules()
val results = engine.strings
results should have size (1)
results.headOption.value shouldBe "Too many CPU peaks : 96.0 97.0"
}
// ======================================================================
it should "be able to search for two consecutives near-by point-in-time events" in {
val drl =
"""package test //#EEX8C
|declare CpuPeak @role(event) @timestamp(timestamp)
| timestamp: java.util.Date
| value:double
|end
|//-----------------
|rule "show event" when
| $peak1:CpuPeak($value1:value, value > 90)
| $peak2:CpuPeak($value2:value,value > 90, this after[30m] $peak1, this != $peak1 )
|then
| insert("Too many CPU peaks : "+$value1+" "+$value2);
|end
|""".stripMargin
val engine = DroolsEngine(drl)
engine.insertJson("""{"timestamp":"2019-01-01T14:00:00Z", "value":95.0}""", "test.CpuPeak")
engine.insertJson("""{"timestamp":"2019-01-01T15:00:00Z", "value":96.0}""", "test.CpuPeak")
engine.insertJson("""{"timestamp":"2019-01-01T15:10:00Z", "value":97.0}""", "test.CpuPeak")
engine.fireAllRules()
val results = engine.strings
results should have size (2)
results should contain allOf("Too many CPU peaks : 95.0 96.0", "Too many CPU peaks : 95.0 97.0")
}
// ======================================================================
it should "be able to search for two consecutive near-by point-in-time events with server distinctions" in {
val drl =
"""package test //#EEX8D
|declare CpuPeak @role(event) @timestamp(timestamp)
| server:String
| timestamp: java.util.Date
| value:double
|end
|//-----------------
|rule "show event" when
| $peak1:CpuPeak($value1:value, value > 90, $server1:server)
| $peak2:CpuPeak($value2:value, value > 90, this after[0,15m] $peak1, this != $peak1, server == $server1 )
|then
| insert("Too many CPU peaks : "+$value1+" "+$value2);
|end
|""".stripMargin
val engine = DroolsEngine(drl)
engine.insertJson("""{"server":"server2", "timestamp":"2019-01-01T15:05:00Z", "value":95.0}""", "test.CpuPeak")
engine.insertJson("""{"server":"server1", "timestamp":"2019-01-01T15:00:00Z", "value":96.0}""", "test.CpuPeak")
engine.insertJson("""{"server":"server1", "timestamp":"2019-01-01T15:10:00Z", "value":97.0}""", "test.CpuPeak")
engine.fireAllRules()
val results = engine.strings
results should have size (1)
results.headOption.value shouldBe "Too many CPU peaks : 96.0 97.0"
}
// ======================================================================
it should "be possible to compute a time-range event from two point-in-time events" in {
val drl =
"""package test //#EEX9
|declare ProcessingStarted @role(event) @timestamp(timestamp)
| timestamp: java.util.Date
| name:String
|end
|declare ProcessingEnded @role(event) @timestamp(timestamp)
| timestamp: java.util.Date
| name:String
|end
|declare ProcessingDuration @role(event) @timestamp(timestamp)
| timestamp: java.util.Date
| howLong:Long
| name:String
|end
|//-----------------
|rule "show event" when
| $start:ProcessingStarted($ds:timestamp, $ts:timestamp.time, $name:name)
| $end:ProcessingEnded( this after $start, $te:timestamp.time, name==$name)
|then
| insert(new ProcessingDuration($ds, $te-$ts, $name));
|end
|""".stripMargin
val engine = DroolsEngine(drl)
engine.insertJson("""{"timestamp":"2019-01-01T14:00:00Z", "name":"A"}""", "test.ProcessingStarted")
engine.insertJson("""{"timestamp":"2019-01-01T15:00:00Z", "name":"A"}""", "test.ProcessingEnded")
engine.fireAllRules()
val result = engine.getModelFirstInstanceAttribute("test.ProcessingDuration", "howLong")
result.collect { case x: java.lang.Long => x }.value shouldBe 3600 * 1000L // make it fail with : +1
info("This is an important example, a typical use case")
info("AND remember to use expires to control your working memory size !")
}
// ======================================================================
it should "be able to catch recent events based on a sliding time window" in {
val drl =
"""package test //EEX10A
|
|declare Event @role(event)
| id:int
| name:String
|end
|
|rule "recent event"
|when
| $event:Event($id:id, $name:name) over window:time(15m)
|then
| insert("OK-"+$id);
|end
|
|""".stripMargin
val e = DroolsEngine(drl, DroolsEngineConfig.configWithEquality)
e.fireAllRules()
e.strings should have size (0)
for {id <- 1 to 10} {
e.advanceTimeMinutes(5)
val event = s"""{"id":$id, "name":"something has happened! #$id"}"""
val eventType = "test.Event"
e.insertJson(event, eventType)
}
e.fireAllRules()
info("It reacts on events of the last 15mn!!! because window:time(15m)")
e.strings should have size (3)
e.strings should contain allOf("OK-10", "OK-9", "OK-8")
}
// ======================================================================
it should "be able to catch recent events based on a sliding length window" in {
val drl =
"""package test //EEX10B
|
|declare AlarmEvent @role(event)
| id:int
| name:String
| criticity:int
|end
|
|rule "recent alarm event"
|when
| AlarmEvent($id:id, $name:name, $mycrit:criticity, criticity>10) over window:length(2)
|then
| insert("OK-"+$id+"-"+$mycrit);
|end
|
|""".stripMargin
val e = DroolsEngine(drl, DroolsEngineConfig.configWithEquality)
e.fireAllRules()
e.strings should have size (0)
for {id <- 1 to 10} {
e.advanceTimeMinutes(5)
val criticity = if (id % 2 == 0) 100 else 1
val event = s"""{"id":$id, "name":"something has happened! #$id", "criticity":$criticity}"""
val eventType = "test.AlarmEvent"
e.insertJson(event, eventType)
}
e.fireAllRules()
info("It reacts on the three last events !!! because window:length(2)")
e.strings should have size (2)
e.strings should contain allOf("OK-8-100", "OK-10-100")
}
// ======================================================================
it should "be able to detect too many events in a short period of time" in {
info("first buggy implementation - the rules fired too many times - see next TU")
val drl =
"""package test //#EEX11
|
|import java.util.LinkedList
|global org.slf4j.Logger logger
|
|declare StartEvent @role(event) @expires(48h)
| host:String
| name:String
|end
|
|rule "Too many restart"
|when
| $event:StartEvent($host:host, $name:name)
| $events:LinkedList(size>5) from collect (
| StartEvent(
| this != $event,
| host==$host,
| name==$name,
| $event after[0s, 10h] this)
| )
|then
| //System.out.println("SIZE EVENTS"+$events.size());
| insert("OK");
|end
|""".stripMargin
val e = DroolsEngine(drl, DroolsEngineConfig.configWithEquality)
e.fireAllRules()
e.strings should have size (0)
val event = """{"host":"zorglub", "name":"apache"}"""
val eventType = "test.StartEvent"
(1 to 10).foreach { _ => e.insertJson(event, eventType); e.advanceTimeHours(5) }
e.fireAllRules()
e.strings should have size (0)
(1 to 10).foreach { _ => e.insertJson(event, eventType); e.advanceTimeMinutes(10) }
e.fireAllRules()
e.strings should have size (1)
}
// ======================================================================
it should "be able to detect too many events in a short period of time revisited" in {
val drl =
"""package test //#EEX11B
|
|import java.util.LinkedList
|global org.slf4j.Logger logger
|
|declare StartEvent @role(event) @expires(48h)
| host:String
| name:String
|end
|
|rule "Too many restart"
|when
| $event:StartEvent($host:host, $name:name) over window:length(1)
| //$event:StartEvent($host:host, $name:name) over window:time(5m)
| $events:LinkedList(size>5) from collect (
| StartEvent(
| this != $event,
| host==$host,
| name==$name,
| this before[0s, 10h] $event)
| )
|then
| insert(new String("OK-"+$events.size()));
| //insert(new String("OK"));
|end
|""".stripMargin
val e = DroolsEngine(drl, DroolsEngineConfig.configWithIdentity)
e.fireAllRules()
e.strings should have size (0)
val event = """{"host":"zorglub", "name":"apache"}"""
val eventType = "test.StartEvent"
(1 to 10).foreach { _ => e.insertJson(event, eventType); e.advanceTimeHours(5) }
e.fireAllRules()
e.strings should have size (0)
(1 to 10).foreach { _ => e.insertJson(event, eventType); e.advanceTimeMinutes(10) }
e.fireAllRules()
e.strings should have size (1)
}
// ======================================================================
"DROOLS" should "be able to detect too many events in a short period of time revisited again" in {
val drl =
"""package test //#EEX11C
|
|import java.util.List
|global org.slf4j.Logger logger
|
|declare StartEvent @role(event) @expires(48h)
| host:String
| name:String
|end
|
|rule "Too many restart"
|when
| $event:StartEvent($host:host, $name:name) over window:length(1)
| $events:List(size>5) from accumulate (
| $event2:StartEvent(
| this != $event,
| host == $host,
| name == $name,
| this before[0s, 10h] $event
| ); collectList($event2)
| )
|then
| insert(new String("OK-"+$events.size()));
| //insert(new String("OK"));
|end
|""".stripMargin
val e = DroolsEngine(drl, DroolsEngineConfig.configWithIdentity)
e.fireAllRules()
e.strings should have size (0)
val event = """{"host":"zorglub", "name":"apache"}"""
val eventType = "test.StartEvent"
(1 to 10).foreach { _ => e.insertJson(event, eventType); e.advanceTimeHours(5) }
e.fireAllRules()
e.strings should have size (0)
(1 to 10).foreach { _ => e.insertJson(event, eventType); e.advanceTimeMinutes(10) }
e.fireAllRules()
e.strings should have size (1)
}
it should "be possible to access the session clock" in {
val drl =
"""package test //#EEX12
|import org.kie.api.time.SessionClock; // Just for information
|
|rule "init"
|duration 10000 // 10 seconds
|when then
| insert("OK-"+drools.getWorkingMemory().getSessionClock().getCurrentTime());
|end
|
|""".stripMargin
val engine = DroolsEngine(drl)
engine.fireAllRules()
engine.strings should have size (0)
engine.timeShiftInSeconds(12)
engine.fireAllRules()
engine.strings should have size (1)
}
it should "be possible to reason on object age (IN FACT NO)" ignore {
val drl =
"""package test //#EEX13
|
|declare Event @role(event) @expires(48h)
| name:String
|end
|
|rule "when too old"
|when
| Event(now() - this.timestamp > 1000) // THERE'S NO now() or SessionClock defaults !!!
|then
| insert("OK")
|end
|
|rule "init"
|when then
| insert(new Event("event"));
|end
|
|""".stripMargin
info("https://stackoverflow.com/questions/34563843/drools-time-based-constraints-and-now")
info("""Drools does not have a continually updated notion of "now" in its absolute sense""")
val engine = DroolsEngine(drl)
engine.fireAllRules()
engine.strings should have size (0)
engine.timeShiftInSeconds(12)
engine.fireAllRules()
engine.strings should have size (1)
}
it should "be possible to reason on timeouts (naive implementation)" in {
val drl =
"""package test //#EEX14
|
|import java.util.Date;
|
|declare TickClock
| @propertyReactive now : Date
|end
|
|
|rule "CreateTickClock"
|when
| not($tickClock:TickClock())
|then
| TickClock tickTocker = new TickClock();
| tickTocker.setNow(new Date(drools.getWorkingMemory().getSessionClock().getCurrentTime()));
| insert(tickTocker);
|end
|
|
|rule "UpdateTickClock"
|//timer (cron: 0/1 * * * * ? ) // every minute
|timer ( 1s 2s ) // every 2 seconds, with 1 second initial delay
|when
| $tickClock:TickClock()
|then
| modify($tickClock) {
| setNow(new Date(drools.getWorkingMemory().getSessionClock().getCurrentTime()));
| }
|end
|
|// ---------------------------------------------------------------------------------
|
|declare Something @role(event)
| peremptionDate: Date
|end
|
|
|rule "AlertOnLatency"
|when
| $tickClock:TickClock($now:now)
| $monitored:Something( peremptionDate < $now)
|then
| insert("OK");
|end
|
|rule "init"
|when then
| insert(new Something(new Date(drools.getWorkingMemory().getSessionClock().getCurrentTime()+5000)));
|end
|
|""".stripMargin
info("inspired from https://stackoverflow.com/questions/34735507/drools-cep-current-date")
info("Always use session clock in KB, never use calls such as new Date() or System.currentTimeMillis()")
info(
"""BUT THIS IS A VERY BAD PRACTICE !!
| AS RULES RELYING ON TickClock WILL FIRE UP CONTINUALLY AT THE SAME frequency as
| for TickClock updates. To Avoid that you'll have to introduce supplementary facts
| to keep in memory that the rule has already been triggered !!!
| SEE NEXT Exemple for a quite better example based on window:time"""
)
val engine = DroolsEngine(drl)
engine.fireAllRules()
engine.strings should have size 0
engine.timeShiftInSeconds(6)
engine.fireAllRules()
engine.strings should have size 1
}
it should "be possible to reason on timeouts (a better implementation)" in {
val drl =
"""package test //#EEX15
|
|declare MyEvent @role(event) @timestamp(timestamp) @duration(validityDelay)
| id: String @key
| timestamp: long
| validityDelay: long
|end
|
|rule "init"
|when then
| insert(new MyEvent("high temperature", 42000, 10000));
|end
|
|rule "find expired events"
|when
| MyEvent($id:id)
| not MyEvent(id == $id) over window:time(20s)
|then
| insert("OK");
|end
|
|""".stripMargin
val engine = DroolsEngine(drl)
engine.fireAllRules()
engine.strings should have size 0
engine.timeShiftInSeconds(50) // t+50s
engine.fireAllRules()
engine.strings should have size 0
engine.timeShiftInSeconds(20) // t+70s
engine.fireAllRules()
engine.strings should have size 1
info(
"""Here in this way the chosen window time period is very important
| as it must coincide with the chosen timeout unfortunately as
| the event start is used to check if the event is over the
| window [-10s,now] frame window; thus the delay makes no sense
| unfortunately.
| Let's check the next example for the right approach also based on sliding windows"""
)
}
it should "be possible to reason on timeouts (the right implementation)" in {
val drl =
"""package test //#EEX16
|
|global org.slf4j.Logger logger
|
|// @duration and @expires are just used to optimize memory management
|// in order to remove events after a given delay at (timestamp + validityDelay + 30s)
|declare MyEvent @role(event) @timestamp(timestamp) @duration(validityDelay) @expires(30s)
| id: String @key
| timestamp: long
| validityDelay: long
|end
|
|declare MyEventEOL @role(event) @timestamp(timestamp)
| id: String @key
| timestamp: long
|end
|
|rule "init"
|when then
| insert(new MyEvent("high temperature", 42000, 20000));
|end
|
|
|rule "setup event EOL"
|when
| MyEvent($id:id, $timestamp:timestamp, $delay:validityDelay)
|then
| insertLogical(new MyEventEOL($id, $timestamp+$delay));
|end
|
|
|rule "take a look into unexpired events"
|when
| MyEvent($id:id)
| $eol:MyEventEOL(id == $id) over window:time(5s)
|then
| logger.info("unexpired " + $eol + " triggered @ "+drools.getWorkingMemory().getSessionClock().getCurrentTime());
|end
|
|
|rule "find expired events"
|when
| MyEvent($id:id)
| not MyEventEOL(id == $id) over window:time(5s)
|then
| insertLogical("OK");
|end
|
|""".stripMargin
val engine = DroolsEngine(drl)
engine.fireAllRules()
engine.strings should have size 0
engine.timeShiftInSeconds(50) // t+50s
engine.fireAllRules()
engine.strings should have size 0
engine.timeShiftInSeconds(15) // t+65s EOL=62 but window:time=[60, 65] as (window:time(5s))
engine.fireAllRules()
engine.strings should have size 0
engine.timeShiftInSeconds(5) // t+70s EOL=62 window:time=[65,70] as (window:time(5s))
engine.fireAllRules()
engine.strings should have size 1
engine.timeShiftInSeconds(22) // t+92s 42s (start) + 20s (validityDelay) + 30 (expired)
engine.fireAllRules()
engine.strings should have size 1
engine.timeShiftInSeconds(1) // t+93s MyEvent has expired, memory automaticall cleaned up
engine.fireAllRules()
engine.strings should have size 0
info(
"""It works perfectly, it worth to be noted that window:time(5s)
|take into account in fact [cur-5, cur] but also [cur, +oo] which means it take
|all future events"""
)
}
it should "expires automatically any events if they can't be involved anymore in any activations" in {
info("By default, an event expires when the event can no longer match and activate any of the current rules.")
info("@expires => overrides the implicit expiration offset calculated from temporal constraints and sliding windows in the KIE base.")
info("unless you use soft expiration : @expires( value = \"48h\", policy = TIME_SOFT )")
}
}
org.scalatest.tools.Runner.main(Array("-oDF", "-s", classOf[UnderstandingEventsRules].getName))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment