Eliminating lingering timers

I’ve got a rules file containing a couple of rules all heavy dependent on timers that are normally not executed unless anything goes wrong, during normal operation they’re constantly being rescheduled. This normally works fine. My problem is that every time the rules file is refreshed (ie I change anything in it) the handlers to all the timers are lost so they aren’t rescheduled (instead the new invokation makes new copies of them), so in the next moments they are executed, making stuff they shouldn’t be.

From my perspective the best thing would be if openHAB took care of this by simply killing all timers in a rules file when it’s refreshed, but I don’t know if thats even possible or what potential backsides it would have? Next best would be if there was a way to finding them and taking care of them myself (like console commands for listing and deleting timers), but I haven’t find anything doing that.

Is this a common problem or is it just me?

1 Like

I am not sure it makes you any happier but this is indeed a common problem, :slight_smile:

Unfortunately, I am not aware of any solution to the problem. I would love to learn about one, though, as I am occasionally bit by this problem as well.

Hmmm. I wonder if this is new behavior. I used to be frustrated by the fact that my Timers went away, not that they stuck around. But in short, once you lose the handle to the Timer there is nothing you can do to cancel it.

Until or if this never gets fixed your options are:

  • write your Timer’s bodies so that when they do fire they check to see if the state is valid for doing whatever it is they do
  • use Expire Binding Based Timers which do become cancelled

I agree with @rlkoshak on the Expire based timers. (Note that they would be defined in an .items file and used in rules files.)

This is an interesting test case — if you have an Expire timer defined in an .items files and you refresh the rules file that references it, does the timer get reset or continue from its current state…

The Expire Timer continues running. For better or worse Expire Timers are tied more to the Items and not tied to the rules at all. If you update ANY .items file your Expire timers will be canceled, which can be a problem. But you can update .rules files all day and the Expire Timers are unaffected.

1 Like

Sort of good. I have my virtual items like expire timers in their own .items file. If I change a different .items file, do the expire timers get reset ?

Yes. Any change to a .items file reinitializes all Items. It has to because otherwise, you couldn’t make an Item a member of a Group in another .items file. The gotcha is that restoreOnStartup won’t reset the Expire binding so all your Expire timers get canceled. :frowning:

So far this really hasn’t been a problem for me so I haven’t put much thought into how to address it. I might do something like have a rule that triggers when my timer Items change from NULL to ON and reissue the ON command. But I’m not sure whether restoreOnStartup will trigger these rules in that case. I’d have to run a test to find out.

OK that is good to know. Are you sure that groups can span .items files ? (Might be new in OH2—definitely did not work in 1.7 etc era – I tried…maybe somewhere in the flow…)

Yes, this has worked since 1.8.?. I’d be in serious trouble if they didn’t. :slight_smile:

OK. Good to know. I was disappointed when I tried it long back (in 1.7-ish world).

Well, the behaviour has been this way since I first started using OH (which, mind you, was not long ago, my first version was 2.0pre-something). It’s a bit like the timers live in a parallell universe where they can never be reached.

I guess you’re correct though that I could work on the content of the Timers so they check states before doing something stupid.

That is actually a pretty apt description. Your only access to that parallel universe is through the Object returned by createTimer. Once you lose that Object you lose your portal to that universe. :alien:

I didn’t lose them! They were taken away from me! I feel robbed!

Try the EXPIRE-based timers. I’ve been converting all my “standard timers” to EXPIRE-based. A few learning-curve items, but I highly recommend them.

Apparently, you can’t create Items in PaperUI that bind to 1.x version bindings (Expire is a 1.x binding). Daniel mentioned somewhere (this thread, another thread, I forget) that he only has Items defined through PaperUI.

Personally, I would probably still create the .items files for the Timers rather than write the Timer code in my rules but I’m not worried about keeping my configuration pure.

Well, keeping the configuration pure is one of the points, I’d rather not having to configure my Items on two different places. Also, I’m not really sure what Expire is capable of? Setting the Item to NULL after a certain time is one thing, but I’m also sending out warning notifications, is that possible with Expire?

Everyone keep telling me Expire is the way to go. I just think it feels like a step in the wrong direction to start making 1.x Items just to start using a binding that is not in phase with the rest of openHAB. Anyone knows if there are any plans on making a 2.x Expire binding?

I keep my expire timer definitions in a file called “virtual.items” along with the _PROXY variants of every switch. I never tried it, but I’d be surprised if you could define such unbound items as PROXY in PaperUI. Have you done that @rlkoshak ?

Yes. See the link above to the Expire Binding Based Timers Design Pattern above.

You can have the Expire binding set an Item to NULL which is the default behavior, update the Item to any valid state, or send a command to any valid state.

In the design pattern and how I use the binding I typically I create a Switch that receives an OFF command when the timer expires. I have a rule that triggers when the Switch received command OFF and that is where I put the code to execute (i.e. the code that would go between the [ | ] for a Timer. To cancel the timer postUpdate(OFF).

The only thing you cannot do with the Expire binding is change the Timer’s time programmatically. You still need to use Timers if the timer has to sleep for a non-predetermined amount of time.

I keep recommending the Expire binding because their use vastly simplifies and reduces the amount of code necessary to achieve the same result: no book keeping, no lambdas, nesting of code is shallower, often rules code can be entirely eliminated. Expire timers survive an update to the .rules files and if one is using restoreOnStartup it is easy to check which Timers were active when OH went down last.

I’m not sure I agree with this statement. OH 2.x was always written with backwards compatibility with 1.x bindings in mind. Using them is certainly not a step backwards. There are many absolutely critical 1.x bindings that remain and perhaps always will remain in a 1.x version (MQTT, autoupdate are two). Reimplementing a binding as a 2.x version is not always a positive experience for the users either, resulting in increased complexity (see Exec 2 compared to Exec1 and weather1 compared to weather2 and yahoo weather). I believe a 2.x version of the Expire binding would equally add in a great deal of complexity for no gains in functionality.

I might start to agree with you when OH 2.5 or so come out, or PaperUI gains the ability to configure OH 1.x bindings on an Item. I know the goal is that everything one needs will be available in OH 2.x through the UIs. But we are not there yet. For now, for many users, limiting oneself to only 2.x version bindings severely cripples OH’s utility.

You can create unbound Items in PaperUI all you want. The problem is you can only supply the stuff between { } to define the Expire binding config in a .items file. So the problem remains, the only way to use Expire (or any other 1.x version binding) is by using .items files.

I’ll continue this thread with another related question: What’s the best way to debug timers that simply don’t happen? I have a timer that should be executed after 20 minutes. I reschedule it a couple of times (always 20 minutes forward) and then suddenly I get no value from the sensor, the rescheduling doesn’t take place and when the code in the timer is supposed to execute: Just nothing. I’ve put calls to logDebug() all over the place to see exactly what happens and the only thing I’m sure of now is that the timer is scheduled to execute but doesn’t. Are timers known to be a bit buggy or is it just on my system?

(Yes I know, @rlkoshak, I should move over to using Expire instead. Leaning more towards it now, but I’d like to get my timers working anyway)

This complete rule looks like this:

rule "Utetemperatur changed"
when
    Item Utetemperatur changed
then
    sendHttpGetRequest("http://www.temperatur.nu/rapportera.php?hash=supersecret&t=" + Utetemperatur.state)
    logDebug("temprule", "Sending " + Utetemperatur.state + " to temperatur.nu")

    if(timer_u == null) {
        logDebug("temprule", "Setting timer")
        timer_u = createTimer(now.plusMinutes(19)) [|
            sendHttpGetRequest("http://www.temperatur.nu/rapportera.php?hash=supersecret&t=" + Utetemperatur.state)
            logDebug("temprule", "Resending " + Utetemperatur.state + " to temperatur.nu and rescheduling timer")
            timer_u.reschedule(now.plusMinutes(19))
        ]
    } else {
        logDebug("temprule", "Rescheduling timer")
        timer_u.reschedule(now.plusMinutes(19))
    }

end

What it does is simply send values to an external service (temperatur.nu) when the outside temperature is changed. And then if the temperature hasn’t changed for 19 minutes it repeats the sending (because temperatur.nu thinks something is wrong if it hasn’t heard from me in 20 minutes). This works 90% of all times but then suddenly I get a “Rescheduling timer” in the log and then nothing more after that. Like the timer simply vanishes…

Not that I’ve experienced or read from others on this forum. For the most part, assuming:

  • you keep a handle on the timer in a global var
  • you do not change any .rules files while the Timer is running
  • you do not explicetly cancel the Timer

Timers are pretty reliable, even really long running ones (hours). I’ve help noone with rescheduleing issues either.

It is hard to say what is going on with your system. Check the logs, are you certain that nothing happened to cause the .rules files to be reloaded when the Timer went away?

I’ve made the recommendation before but understand your reasons for not wanting to use them. I like them but that doesn’t mean I judge those who don’t use them. I’d like to get your Timers working as is as well.

I assume timer_u is a gloval val initialized to null, correct?

Under what circumstances would this Timer ever be canceled? As written right now, the Timer never gets cancels and just keeps being rescheduled forever. Is this correct?

If so I suspect the problem is your Timer is being garbage collected. This might be worth reporting as a bug on the ESH repo, though I imagine Kai’s initial reaction will be “you should not be using timers like this.”

A better way to implement something that is to run every 19 minutes forever is to use a cron triggered rule instead. Something like:

rule "get Utetemperature changed"
when
    Item Utetemperatur changed or
    Time cron "0 */19 * * * ? *"
then
    sendHttpGetRequest("http://www.temperatur.nu/rapportera.php?hash=supersecret&t=" + Utetemperatur.state)
    logDebug("temprule", "Resending " + Utetemperatur.state + " to temperatur.nu and rescheduling timer")
end

The timing won’t be exactly the same (it will post every 19 minutes AND post the changes rather than posting every 19 minutes after the last temperature change) but I think the end result will work for this service.

If you must have exactly the same timing, instead of rescheduling the Timer forever, create a new one each time. This gets tricky because it is really hard to write code inside a timer to recreate itself without hitting an infinite regression. Luckily I wrote up a way to do it here.

Honestly, I can’t say I would recommend this recursive timers approach. It is IMHO really kludgy. But it should work.

Another perhaps less kludgy way to do it could be to use an Unbound Switch to retrigger the rule when the Timer expires. That would look something like:

rule "Utetemperatur changed"
when
    Item Utetemperatur changed or
    Item Utetemperature_Timer received command
then
    sendHttpGetRequest("http://www.temperatur.nu/rapportera.php?hash=supersecret&t=" + Utetemperatur.state)
    logDebug("temprule", "Sending " + Utetemperatur.state + " to temperatur.nu")

    timer_u.?cancel // I'm not sure I have the ? and the . in the right order
    timer_u = createTimer(now.plusMinutes(19), [|
        logDebug("temprule", "Resending " + Utetemperatur.state + " to temperatur.nu and rescheduling timer")
        Utetemperature_Timer.sendCommand(ON)
        timer_u = null
    ])
end

The .?cancel is a shortcut way of doing:

if(timer_u != null) timer_u.cancel

In the above, when either Utetemperature changes or Utetemperature_Timer receives a command the Rule triggers. In either case we send the temp and log it.

If the rule triggered because of a temp change then we cancel the existing timer and create a new one. If the rule triggered because of the Timer then the Timer is already null and we create a new one.

When the Timer goes off it logs and sends a command to the Timer Item which triggers the rule.