I’ve been optimising some of my common/repetitive rules by condensing common code into scripts, then calling them in individual rules by calling rules.runRule() and passing context data, just like the idea of using functions.
Generally this idea works fine, but there are some pitfalls with the asynchronous nature of event handling vs calling functions in a truly synchronous environment.
Sometimes OH will need to send ~20 commands to items in one operation, which will each call a common script. This results in a few of the script executions failing to run, giving the log error: Failed to execute rule ‘rule_name’ with status ‘RUNNING’
I guess this makes sense if the script takes a finite amount of time to run, and is “locked” for that duration, even while other scripts are running in the background and trying to call it.
Is there a more robust way of calling scripts with rules.runRule() that can check the script before calling?
In the case of multiple items/commands at once, it’s not too much of a problem for me to generate individual scripts, and perhaps it may be more performant if all operations are done in their respective scripts.
However as a general idea, would this be a better way of calling other scripts if there’s a chance of execution clashes?
function runScript() {
let err = 0;
try {
rules.runRule();
}
catch {
err = 1;
}
finally {
return err;
}
}
while (retries < 10) {
if (runScript()) {
retries++;
console.log('Retrying script call in UID: '.concat(ctx.ruleUID));
}
else {
retries = 10;
}
}
No and this really isn’t a good approach. You should put your common code into a library. There are docs for how to do that in the add-on readme.
Only one instance of a rule can run at a time meaning you either end up with high latency or errors like this. Scripts and run rule are not a suitable replacement for libraries in JS.
Instead of fighting it, the best approach is to put common code into a library.