Working With Session Clock:Drools(BRMS)

8.5. Session Clock

Reasoning over time requires a reference clock. Just to mention one example, if a rule reasons over the average price of a given stock over the last 60 minutes, how the engine knows what stock price changes happened over the last 60 minutes in order to calculate the average? The obvious response is: by comparing the timestamp of the events with the “current time”. How the engine knows what time is now? Again, obviously, by querying the Session Clock.

The session clock implements a strategy pattern, allowing different types of clocks to be plugged and used by the engine. This is very important because the engine may be running in an elements of different scenarios that may require different clock implementations. Just to mention a few:

  • Rules testing: testing always requires a controlled environment, and when the tests include rules with temporal constraints, it is necessary to not only control the input rules and facts, but also the flow of time.
  • Regular execution: usually, when running rules in production, the application will require a real time clock that allows the rules engine to react immediately to the time progression.
  • Special environments: specific environments may have specific requirements on time control. Cluster environments may require clock synchronization through heart beats, or JEE environments may require the use of an AppServer provided clock, etc.
  • Rules replay or simulation: to replay scenarios or simulate scenarios it is necessary that the application also controls the flow of time.

8.5.1. Available Clock Implementations

Drools 5 provides 2 clock implementations out of the box. The default real time clock, based on the system clock, and an optional pseudo clock, controlled by the application.

By default, Drools uses a real time clock implementation that internally uses the system clock to determine the current timestamp.

To explicitly configure the engine to use the real time clock, just set the session configuration parameter to real time:

KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();config.setOption( ClockTypeOption.get("realtime") );

Drools also offers out of the box an implementation of a clock that is controlled by the application that is called Pseudo Clock. This clock is specially useful for unit testing temporal rules since it can be controlled by the application and so the results become deterministic.

To configure the pseudo session clock, do:

KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();config.setOption( ClockTypeOption.get("pseudo") );

As an example of how to control the pseudo session clock:

KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();conf.setOption( ClockTypeOption.get( "pseudo" ) );KieSession session = kbase.newKieSession( conf, null );SessionPseudoClock clock = session.getSessionClock();
// then, while inserting facts, advance the clock as necessary:FactHandle handle1 = session.insert( tick1 );clock.advanceTime( 10, TimeUnit.SECONDS );FactHandle handle2 = session.insert( tick2 );clock.advanceTime( 30, TimeUnit.SECONDS );FactHandle handle3 = session.insert( tick3 );

8.6. Sliding Windows

Sliding Windows are a way to scope the events of interest by defining a window that is constantly moving. The two most common types of sliding window implementations are time based windows and length based windows.

The next sections will detail each of them.

Important

Sliding Windows are only available when running the engine in STREAM mode. Check the Event Processing Mode section for details on how the STREAM mode works.

Important

Sliding windows start to match immediately and defining a sliding window does not imply that the rule has to wait for the sliding window to be “full” in order to match. For instance, a rule that calculates the average of an event property on a window:length(10) will start calculating the average immediately, and it will start at 0 (zero) for no-events, and will update the average as events arrive one by one.

8.6.1. Sliding Time Windows

Sliding Time Windows allow the user to write rules that will only match events occurring in the last X time units.

For instance, if the user wants to consider only the Stock Ticks that happened in the last 2 minutes, the pattern would look like this:

StockTick() over window:time( 2m )

Drools uses the “over” keyword to associate windows to patterns.

On a more elaborate example, if the user wants to sound an alarm in case the average temperature over the last 10 minutes read from a sensor is above the threshold value, the rule would look like:

Example 8.5. aggregating values over time windows

rule "Sound the alarm in case temperature rises above threshold"
when
TemperatureThreshold( $max : max )
Number( doubleValue > $max ) from accumulate(
SensorReading( $temp : temperature ) over window:time( 10m ),
average( $temp ) )
then
// sound the alarm
end

The engine will automatically disregard any SensorReading older than 10 minutes and keep the calculated average consistent.

Important

Please note that time based windows are considered when calculating the interval an event remains in the working memory before being expired, but an event falling off a sliding window does not mean by itself that the event will be discarded from the working memory, as there might be other rules that depend on that event. The engine will discard events only when no other rules depend on that event and the expiration policy for that event type is fulfilled.

8.6.2. Sliding Length Windows

Sliding Length Windows work the same way as Time Windows, but consider events based on order of their insertion into the session instead of flow of time.

For instance, if the user wants to consider only the last 10 RHT Stock Ticks, independent of how old they are, the pattern would look like this:

StockTick( company == "RHT" ) over window:length( 10 )

As you can see, the pattern is similar to the one presented in the previous section, but instead of using window:time to define the sliding window, it uses window:length.

Using a similar example to the one in the previous section, if the user wants to sound an alarm in case the average temperature over the last 100 readings from a sensor is above the threshold value, the rule would look like:

Example 8.6. aggregating values over length windows

rule "Sound the alarm in case temperature rises above threshold"
when
TemperatureThreshold( $max : max )
Number( doubleValue > $max ) from accumulate(
SensorReading( $temp : temperature ) over window:length( 100 ),
average( $temp ) )
then
// sound the alarm
end

The engine will keep only consider the last 100 readings to calculate the average temperature.

Important

Please note that falling off a length based window is not criteria for event expiration in the session. The engine disregards events that fall off a window when calculating that window, but does not remove the event from the session based on that condition alone as there might be other rules that depend on that event.

Important

Please note that length based windows do not define temporal constraints for event expiration from the session, and the engine will not consider them. If events have no other rules defining temporal constraints and no explicit expiration policy, the engine will keep them in the session indefinitely.

Software Developer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store