Lifetime of items created in a script

If I create some items programatically, what will happend to the item if I remove/unload the Javascript file?

var groupConfig = {
  type: 'Group',
  name: 'gMyTestGroup',
  label: 'Test group',
  giBaseType: 'Switch',
  groupFunction: new GroupAndFunc(ON,OFF)
}
newItem = items.addItem(groupConfig);

Will the item gMyTestGroup be removed automatically if the script is removed, or how does this work?

Until someone can confirm, this is easy enough to test. Just run your script, then delete or rename the extension so the script gets unloaded.

1 Like

It’s been a few versions since I’ve tested this sort of thing. Be sure to try it out and come back and report what you find.

But my understanding based on how it used to work and based on what I know of how the ItemRegistry works, once the Item is created, whether it be from a rule or through the API some other way, it persists until it’s explicitly deleted. In other words, the Item is not tied to the rule that created it.

It’s for this reason that when I used to create Items from Jython rules way back in the day, I’d make sure to delete those Items in the unloaded function to ensure that rules would clean up after themselves and not leave orphaned automatically created stuff.

I’m not sure if unloaded still exists as a concept in JS Scripting or jRuby these days. It’s definitely not something that exists in UI rules.

I have now done my testing. My file test-1.js looks like this:

var logger = log('test');
var myItemName = 'switchMyTest'

// Example
require('@runtime').lifecycleTracker.addDisposeHook(() => {
  items.removeItem(myItemName)
  if (items.getItem(myItemName, true) == null) {
    logger.info("Item '{}' was removed sucessfully....", myItemName);
  }
  else {
    logger.error("Item '{}' was NOT removed....", myItemName);
  };
  
  logger.info("Script 'test-1.js' is unloaded...");
    
});



  items.addItem({name: myItemName, type:'Switch', label:'My Test Switch'});
  if (items.getItem(myItemName, true) != null) {
    logger.info("Item '{}' was created sucessfully....", myItemName);
  }
  else {
    logger.error("Item '{}' was NOT created....", myItemName);
  };

logger.info("Script 'test-1.js' is loaded....");

The results shows that you are correct, if I omit the addDisposeHook I see the following line in my log files:

2024-01-08 20:39:48.312 [ERROR] [b.automation.script.javascript.stack] - Failed to execute script:
javax.script.ScriptException: java.lang.IllegalArgumentException: Cannot add element, because an element with same UID (switchMyTest) already exists.

Well I am also looking at how to retire my Jython rules, and I already found the equivalent to unload in the deinitialization hook as you can see in the code sample :slight_smile:.

I wonder if that would work from a UI rule…

I mainly only created Items from a Rule in cases where I had the equivalent of Rule Templates. Now that we have real rule templates I’ve come into cases where I’d like to create Items when they don’t exist but I’ve avoided it because I never spent the time to figure out how to delete them on unload.

NOTE: rule templates are only supported through UI rules.

A quick test seems to show it doesn’t work from a UI rule as I had hoped but there is a chance.

I created a rule with

require('@runtime').lifecycleTracker.addDisposeHook(() => {
  console.info('Rule is disposed');
});
console.info('Rule ran');

Disabling or deleting the rule without first running it resulted in nothing in the logs, as makes sense. The above doesn’t run until the rule is run.

After running the rule when I disable the rule or delete the rule I do see ‘Rule is disposed’, but I see one log for each time the rule runs. That’s not going to be acceptable.

But I might be able to work around that by putting a flag into the private cache after the hook is added and only add the hook when that flag doesn’t exist.

cache.private.get('disposehook', () => {
  require('@runtime').lifecycleTracker.addDisposeHook(() => {
    console.info('Rule is disposed');
  });
  return true;
});

console.info('Rule ran');

That appears to work. I’m not entirely certain I like it, but it works. No matter how many times I run the rule only one hook gets registered.

One thing to note is disabling a rule disposes of the rule so the hook gets called then, not just when the rule is unloaded/deleted. Consequently I’m not 100% certain this is going to be very useful to me unfortunately. I wouldn’t want the Item to be deleted every time the OH restarts (for instance).

FTR, jruby creates things and items very differently to how it’s done in js-scripting. It does not touch the ManagedProvider at all, and instead, has its own Provider for Things and Items. As a result, things and items are removed when the script unloads (or when openhab stops), and the clean up is done for you.

Because of this, it can be a direct replacement for .things and .items file, by creating them in a script that is set to start at a lower startlevel (e.g. placed in conf/automation/ruby/sl30/create_my_things_and_items.rb).

I’ve converted my .things and .items file into jruby now.

PS: it can of course also create/modify/delete ManagedProvider items if desired, because it has full access to openhab’s API.

Woow, this is cool. Is it documented somewhere ? I managed to create them at startup with start level tracking but this is even better.

Are you referring to the sl30 bit?

Exactly !

1 Like

Thanks, I totally forgot about this.