Skip to content

[Bug]: Script mirror resets enabled and engine (instance) when a mirrored file changes #2396

Description

@knodge-gem

I'm sure that

  • This issue is still present in the current beta version of this adapter
  • There is no other (open) issue with the same topic (use the search!)
  • This issue is not described in the adapter documentation / FAQ (read the docs!)

Script type

TypeScript

The problem

When a mirrored script file is changed on disk, the mirror writes its cached copy of the script object
back to the database with only the new source. The cache (dbList) is only refreshed when the
source of the object changes, so changes made in the admin UI to common.enabled or common.engine
since the last adapter start (or last source change) are silently reverted.

Code (same in 9.0.18 and current master / 10.3.0), src/lib/mirror.ts:

  • onObjectChange() (master ~L615): this.dbList[id] = obj is only executed if
    this.dbList[id].common.source !== obj.common.source. Changes to enabled / engine don't
    update the cache.
  • onFileChange() (master ~L530): on a changed file, the cached object is written back via
    setForeignObject(id, this.dbList[id]) with only common.source replaced → stale enabled and
    engine overwrite the current values.

To Reproduce

  1. Enable script mirroring in javascript.0.
  2. Create a script in the UI (disabled, instance javascript.0), let it be mirrored to disk.
  3. In the UI, enable the script and/or move it to javascript.1. Don't change its source.
  4. Change the script file on disk (e.g. git pull / git push into the mirror directory, or any editor).
  5. The script is now disabled again and back in javascript.0.

Expected behavior

Only common.source is updated from disk. enabled, engine and all other properties keep their
current values.

Suggested fix

In onObjectChange() always refresh the cache for script objects, e.g.

if (this.dbList[id]) {
    const sourceChanged = this.dbList[id].common.source !== obj.common.source;
    this.dbList[id] = obj; // always keep the cache in sync (enabled, engine, ...)
    if (sourceChanged || !this.diskList[id] || this.diskList[id].source !== obj.common.source) {
        this.diskList[id] = { ts: 0, source: obj.common.source, name: file };
        this._writeFile(id);
    }
}

Alternatively, in onFileChange() use extendForeignObject(id, { common: { source } }) instead of
writing the whole cached object.

Versions

  • Adapter version: 10.1.3 (reproduced), first seen with 9.0.18; relevant code unchanged in master (10.3.0)
  • JS-Controller: 7.2.2
  • Node.js: 24.21.0
  • Operating system: Docker buanet/iobroker:latest on Raspberry Pi 5

Additional context

Observed with a Git-based workflow: scripts are edited on a PC and pushed into the mirror directory.
After every push the touched script fell back to javascript.0, and a script enabled in the UI after
its creation was disabled again.

Reproduced with 10.1.3 right after an adapter restart: script common.JSON_Test (disabled) moved to
javascript.2 in the UI (object written by system.adapter.admin.0, engine = javascript.2).
Then one comment line added to the file on disk. Afterwards the object was written by
system.adapter.javascript.0 with the new source and engine = system.adapter.javascript.0.

iobroker.current.log (in debug mode!)

No response

Version of nodejs

24.21.0

Version of ioBroker js-controller

7.2.2

Version of adapter

10.1.3

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions