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.
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?
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.