Skip to content

Driver source paths resolve only at startup: swapping a local driver for a managed artifact kills the driver until a full restart #840

Description

@Leitet

Summary

Driver Lua source paths are resolved once, at startup. Both the config watcher and POST /api/drivers/{name}/restart reuse the cached absolute path, so when a driver's source legitimately moves — the exact flow the device repository is built for — the driver dies instead of re-resolving, and only a full process restart recovers. On a site whose site meter is that driver, dispatch is inhibited for the whole window.

Hit on real hardware today (v1.15.0, the FoxESS site) while swapping the driver from a local override file to the managed signed beta artifact.

Reproduction (observed live)

  1. Driver configured lua: drivers/foxess_h3_smart.lua; the file exists in the user drivers dir (local override).
  2. Install the managed artifact for the same logical path: POST /api/device_repository/drivers/foxess_h3_smart/install {"channel":"beta","version":"0.9.0"} → active symlink appears in driver-repository/active/, ftw_signed: true.
  3. Move the user file aside (the point of the swap) and POST /api/drivers/foxess/restart
    load lua: read /app/data/drivers/foxess_h3_smart.lua: no such file or directory — the restart reuses the path resolved at startup instead of re-running resolution, which would have found the managed symlink.
  4. Touch config.yaml to nudge the watcher → log shows driver removed | name=foxess and then site dispatch inhibited — reverting controllable drivers to autonomous | reason=site_meter_stale. No driver added follows. The managed symlink existed and was valid the whole time.
  5. POST /api/restart → startup resolution runs (config.ResolveDriverPaths: user dir → managed active dir → bundled), logs driver added | path=/app/data/driver-repository/active/foxess_h3_smart.lua, full recovery.

Site-meter outage in step 3–5: about 4 minutes, dispatch correctly inhibited, inverter in native self-use throughout (the safety net behaved exactly right — this is a liveness bug, not a safety bug).

Where

config.ResolveDriverPaths mutates Drivers[i].Lua in place and runs from main.go at startup only. The watcher's reload and the driver restart endpoint both act on the already-resolved absolute path. The fall-through order (user dir → managed active dir → bundled) is correct and did the right thing the one time it ran.

Suggested direction

Re-run path resolution wherever a driver is (re)loaded — the restart endpoint and the reload path — rather than only at startup. Naturally adjacent to #761's single shared configreload.Apply: one apply path that re-resolves would fix both entry points at once. Worth a test that swaps a driver source between the three resolution tiers at runtime, since the device-repository install flow makes that transition a first-class operation now (it is precisely how a site adopts a channel driver over a local file).

Happy to validate a fix on the same hardware.

🤖 Generated with Claude Code

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