Question about rules for understanding

Hello, small question for my understanding of rules:
I have a test rule:

var Timer t_timer = null

rule "Test"
when
	Item x changed or
    Item y changed
then
	logInfo("Test","Rule activated")
	if (t_timer === null)
	{
		logInfo("Test","Timer starts")
		t_timer = createTimer(now.plusMinutes(1)) [|
			logInfo("Test","Timer finished")
			t_timer = null
		]
	}
	else
	{
		logInfo("Test","Timer cancel")
		t_timer.cancel
		t_timer = null
	}
end

Now if I change x or y than the rule gets fired. If I do this a second time the timer get canceled. Ok so far.
But now imagine x and y change the same time. In this case the rule get fired 2 times and 2 timers start with the same name t_timer. if I try to cancel than I only can do it for the last started timer the first one always runs till the time elapsed.
Is this the correct behavior? Thanks

That’s what I would expect to happen, yes, if you can trigger the rule fast enough.

Think of the variable, t_timer in this case, as a handle, pointer, or reference to a created timer. It is not a container of the timer. createTimer sets up the block of code and a schedule to run it, and returns a reference. If you destroy or overwrite the reference, it does not change the schedule which will just carry on and eventually execute its code block.

It’s good practice then to do any testing like if (t_timer === null) as early on in your rule as you can, and that is usually sufficient.
But that does still leave a finite time between trigger event and test pass/fail, for multiple starts of the rule to mess up.
In some real rule you might code inventively to get around it, or more likely choose your triggers carefully, depending what the actual task is.

Someone will be along in a minute to point out that NGRE JSR223 rules are not affected by this, because they don’t multi-thread i.e. you cannot have multiple starts of the same rule. :wink:

Thanks a lot for helping me to understand

I am curious on that, wouldn’t the variable t_timer allways be pointing to the same globally declared Timer? If not, how coud a second run cancel the timer?

If you do

t_timer = createTimer(now.plusMinutes(1)) [|
// this creates a scheduled timer and puts a reference in the variable

.... //later

t_timer = createTimer(now.plusMinutes(1)) [|
// this creates a scheduled timer and puts a reference in the variable

Now you’ve got two timers scheduled, but only have a reference to the second one.
There’s no way to stop or cancel the first one, you have lost all hope of communicating with it by losing (overwriting) your only reference. You cannot even discover if it exists.

t_timer is not THE timer, it is only a pointer.
THE timer is anonymous, invisible, only accessible by that reference pointer.

1 Like

Understood!
In my words, this happens if both running (identical) rules enter the if clause before either one creates the timer.

1 Like

… which will never happen with the new rule engine…

@rossko57 how do you enable post prediction in forum topics? :rofl: :rofl:

2 Likes