Something seems to go wrong when calling standard libraries from a function called by timer

I created a sample script:

var { TimerMgr } = require('openhab_rules_tools');
var tm = cache.private.get('TimeManager', ()=>TimerMgr());

function Processor(timerKey) {
  this.timerKey = timerKey;
  this.timerCounter = 0;
}

(function () {
  this.do = function () {
    this.timerCounter = this.timerCounter + 1;
    tm.cancel(this.timerKey);
    if(this.timerCounter==10){
      return;
    }
    const intervalStr = 'PT3s';
    console.warn("1:"+this.timerCounter+" "+intervalStr);
    const { time } = require('openhab');
    const inerval =  time.toZDT(intervalStr);
    console.warn("2:"+this.timerCounter+" "+inerval);
    tm.check(this.timerKey, intervalStr, ()=>{this.do();}, true, ()=>{}, 'Test2Timer');
    console.warn("3:"+this.timerCounter);
  };
}).call(Processor.prototype);


var processor = new Processor('test2Timer_'+ruleUID);
console.warn("0");
//processor.do();
tm.check(this.timerKey, 'PT3s', ()=>{processor.do();}, true, ()=>{}, 'Test2Timer');

It failed on calling time.toZDT when the function called for the second time:

2024-05-11 12:51:04.220 [WARN ] [nhab.automation.script.ui.baf14095a8] - 0
2024-05-11 12:51:07.235 [WARN ] [nhab.automation.script.ui.baf14095a8] - 1:1 PT3s
2024-05-11 12:51:07.248 [WARN ] [nhab.automation.script.ui.baf14095a8] - 2:1 2024-05-11T12:51:10.243+03:00[SYSTEM]
2024-05-11 12:51:07.261 [WARN ] [nhab.automation.script.ui.baf14095a8] - 3:1
2024-05-11 12:51:10.257 [WARN ] [nhab.automation.script.ui.baf14095a8] - 1:2 PT3s
2024-05-11 12:51:10.279 [WARN ] [ore.internal.scheduler.SchedulerImpl] - Scheduled job 'Test2Timer' failed and stopped
org.graalvm.polyglot.PolyglotException: null
	at <js>._is24Hr(/node_modules/openhab.js:2) ~[?:?]
	at <js>._parseString(/node_modules/openhab.js:2) ~[?:?]
	at <js>.toZDT(/node_modules/openhab.js:2) ~[?:?]
	at <js>.this.do(<eval>:19) ~[?:?]
	at <js>.:=>(<eval>:21) ~[?:?]
	at <js>.:=>(/openhab/conf/automation/js/node_modules/openhab_rules_tools/timerMgr.js:66) ~[?:?]
	at <js>.callbackFn(/node_modules/openhab.js:2) ~[?:?]
	at com.oracle.truffle.polyglot.PolyglotFunctionProxyHandler.invoke(PolyglotFunctionProxyHandler.java:154) ~[bundleFile:?]
	at jdk.proxy1.$Proxy1565.run(Unknown Source) ~[?:?]
	at org.openhab.automation.jsscripting.internal.threading.ThreadsafeTimers.lambda$0(ThreadsafeTimers.java:85) ~[bundleFile:?]
	at org.openhab.core.internal.scheduler.SchedulerImpl.lambda$12(SchedulerImpl.java:189) ~[?:?]
	at org.openhab.core.internal.scheduler.SchedulerImpl.lambda$1(SchedulerImpl.java:88) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) [?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) [?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) [?:?]
	at java.lang.Thread.run(Thread.java:840) [?:?]

Am I right or I do something wrong?

I don’t see anything obviously wrong and you are correct in that it appears to be happening in the time.toZDT call.

Do some experiments in -Scratchpad- and see if you can generate some Strings that time.toZDT fails to parse and file an issue.

I myself have recently encountered a weird case where “08:00” is failing but only some of the time and I get a different error so I can’t say if it’s the same issue as you are having.

But since you are using OHRT, why not use a looping timer for this? That kind of what it’s there for. That will make the whole rule a lot simpler. TimerMgr is really meant for cases where you have one rule triggered by lots of different Items and you need to manage one separate timer per each Item. Using TimerMgr to handle just one single timer, as is done here, is awkward.

I also don’t understand the whole “Processor” code at all. Why not use the cache for the count and hard code the key?

var { LoopingTiemr } = require('openhab_rules_tools');
var lt = cache.private.get('LoopingTimer'); // you are using the private cache so there's no chance of naming conflict with another rule
var interval = 'PT3S';

console.warn('0');

// Reschedule if LT already exists
if(lt !== null) lt.timer.?cancel();

// Create the looping timer
lt = LoopingTimer();

// Add the timer to the cache
cache.private.put('LoopingTimer', lt);

// Start the timer looping
var loopCount = 0;
lt.loop( () => {
  loopCount++;
  if(loopCount >= 10) return null; // stop looping

  console.warn('1:'+loopCount+' '+interval);
  const parsed = time.toZDT(interval);
  console.warn('2:'+loopCount+' '+parsed);

  return parsed; // will run the loop again at interval
}, interval);

There’s nothing special you need to do to store loopCount, it’s saved in the context in the timer function. But if you did need to save it outside of that, use the cache, not this to store it.

The looping timer reschedules itself based on what the timer function returns. If it return null the loop stops. If it returns something that time.toZDT() can handle it reschedules the next run for that time.

First of all, thanks a lot for the tip to use LoopingTimer. It is the particular thing I need.

But I am worrying about the problem in calling time.toZDT. It is failing with any string interval (PT3s, PT10s, PT5s), but only if it is called in function called by timer which started in function called by timer (look at the log, the first call was succeed, but the second call failed). It looks like a bug inside the engine and it may appear in other cases.

There is a lot of awkwardness in how the code is written which could be getting in the way here too so I can’t really draw any conclusions about what is causing the problem. I do know that I use a couple hundred timers in my rules and I use the ISO8601 duration strings for all of them.

You will notice though that the LoopingTimer example I posted also parses the duration String inside the Timer’s function. If parsing really is a problem because it’s inside a timer function, the same error will occur there too.

The advantage is there won’t be all that extra stuff getting in the way like the reimportation of time, trying to store variables between runs in this, the odd way to define the function within a function, etc.