fix(rig): the LED watcher had three lifecycles and two could run at once — now it is gear
The board's colours only persist because a daemon holds a model of every control
and repaints from it. That daemon had no home. It could be started three ways:
1. by hand, tools/lcxl-leds.py --watch
2. by gig-up.sh, which `setsid`-spawned its own copy (GIG_LEDS=watch)
3. as a *transient* systemd unit, which is how it was actually running today
(systemd-run --unit=lcxl-leds-watch)
Every one of those is wrong in a different way. (1) dies with the terminal. (2)
does not know about (3), so launching gig-up on a machine that already had the
watcher up gave you TWO processes writing SysEx to the same LCXL, fighting over
every LED — and neither of them wrong enough to look broken, which is the worst
kind of bug this rig produces. (3) has no file on disk, so it evaporates at the
next reboot and the board silently stops persisting colours.
PLN, on being shown the three: "watcher must be a saved tool part of gear indeed".
So: tools/lcxl-leds-watch.service, symlinked into ~/.config/systemd/user/ the same
way parvagues-bridge.service already is, enabled, WantedBy=default.target — it
starts at boot with linger, before any login. gig-up.sh no longer spawns anything;
it `systemctl --user restart`s the unit, which is idempotent AND guarantees exactly
one owner even if a stale watcher survived a crash. One owner of the board, always.
Two details worth the ink:
- StartLimitIntervalSec=0 belongs in [Unit], not [Service]. Put in [Service] systemd
says "Unknown key ... ignoring" — a warning in the journal nobody reads — and the
default limit of 5 restarts in 10 s stays in force. The LCXL is hot-pluggable and
usually absent at boot, so with Restart=always/RestartSec=10 the unit would burn
its five retries and fall into `failed`, board dark for the rest of the session.
A silent failure one section heading away from working. Caught it because the
first install DID log the warning; fixed and re-verified with systemd-analyze.
- Cost, measured from the transient unit's own accounting before replacing it:
2.140 s CPU over 1 h 53 m wall = 0.03% of a core, 14.5 M peak RSS. The watcher
forks a helper per LED write, which is a real throughput problem for the 1-2 s
paint lag — but it is emphatically not a load problem, so it can stay Nice=5 /
CPUWeight=20 and never be a candidate when hunting xruns.
Verified: unit enabled + active, systemd-analyze verify clean, no Unknown-key
warning on reload, `bash -n gig-up.sh` clean, and exactly one watcher process
owned by the unit (MainPID matches, NRestarts=0). Note `pgrep -cf 'lcxl-leds.py
--watch'` reports 2 — it counts the shell running the pgrep pipeline itself. Read
the process list, not the count.
Closes #85.
Showing
tools/lcxl-leds-watch.service
0 → 100644
Please
register
or
sign in
to comment