Search code examples
droolskiedrools-fusion

Drools Fusion SessionPseudoClock Not working as expected


I am trying to set KieSession date to same date with the date variable in my object before running the rules. I use this configuration to create my KieSession

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

Before running the rules I use advanceTime() to set the date of the session to desired date.

final SessionPseudoClock clock = kSession.getSessionClock();
clock.advanceTime(object.getDate().getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);

final List<Command<?>> commands = new ArrayList<>();

commands.add(CommandFactory.newInsertElements(objects)
commands.add(CommandFactory.newInsert(object, "object"));

final ExecutionResults results = kSession.execute(CommandFactory.newBatchExecution(commands));

This resulted misfires in the rules that uses sliding windows. Lets say checking the objects that passed in 1 hour and I don't have any in the last hour. I only have 3 objects day before. Here is an example dataset of objects.

objects: [
  {
    clientId: "id",
    date: 2021-02-09T12:00:38.249Z,
    ...
  }
  {
    clientId: "id",
    date: 2021-02-09T13:00:38.249Z,
    ...
  }
  {
    clientId: "id",
    date: 2021-02-09T14:00:38.249Z,
    ...
  }
]

I have a rule which checks if there are more than 2 objects with the same clientId over 1 hour.

$object : Object($clientId : clientId)
List( size > 2 ) from collect ( Object( this before $object, clientId == $clientId ) over window:time(1h))

When I pass an object with these values. The rule above returns true but we clearly don't have any objects that has a date within last hour.

  { clientId: "id", date: 2021-02-10T14:00:38.249Z, ... }

I believe this is broken because of the new configuration as it was working previously (when I did not try to change session clock) but I want session date to be equal to object date. Anyone has ideas what is the problem here and how to fix it?


Solution

  • As Roddy of the Frozen Peas made the remark, you need to manipulate SessionPseudoClock in between every insert of your events. I'd implement a new Command, extend InsertElementsCommand and @Override it's execute method:

        @Override
        public Collection<FactHandle> execute(Context context) {
    
            KieSession kSession = ((RegistryContext) context).lookup(KieSession.class);
            List<FactHandle> handles = new ArrayList<>();
    
            Object workingMemory = StringUtils.isEmpty(super.getEntryPoint()) ?
                    kSession :
                    kSession.getEntryPoint(super.getEntryPoint());
    
            SessionPseudoClock clock = kSession.getSessionClock();
    
            super.objects.forEach(event -> {
                clock.advanceTime(((YourObject) event).getDate().getTime() - clock.getCurrentTime(), TimeUnit.MILLISECONDS);
                handles.add(((EntryPoint) workingMemory).insert(event));
            });
    
            ...
    
            return handles;
        }
    

    and instead of:

    commands.add(CommandFactory.newInsertElements(objects));
    

    I'd:

    commands.add(new YourInsertElementsCommand(objects));