fix(udev): scope SIGUSR2 hotplug signal to ceralive.service main pid (stop killing avahi/mDNS)#149
Merged
Merged
Conversation
Contributor
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
andrescera
force-pushed
the
fix/udev-sigusr2-scoped-kill
branch
2 times, most recently
from
July 16, 2026 21:03
eaa6d1f to
ff2bcdd
Compare
The two USB/audio hotplug udev rules signalled the backend with `pkill -o -SIGUSR2 -f ceralive`. `pkill -f` substring-matches the full command line of every process. Avahi renames its process title to `avahi-daemon: registering [<hostname>.local]` after registering a hostname, and this device's hostname is `ceralive.local` — so avahi-daemon matched the broad pkill and took SIGUSR2 (default disposition: terminate) on every hotplug. With no Restart= on avahi-daemon.service, mDNS stayed dead until reboot. Deliver the signal through `systemctl kill --kill-whom=main --signal=SIGUSR2 ceralive.service` instead — the same cgroup-scoped idiom already used by ceralive-addon-reconciler.service. --kill-whom=main preserves the old `pkill -o` single-process intent, so the whole-cgroup default can never collaterally SIGUSR2-terminate srtla_send/bcrpt (which share the unit cgroup while streaming and do not handle SIGUSR2). systemctl kill is safe from a udev RUN+= rule: it sends the signal via a synchronous PID-1 D-Bus call and creates no job, so the deadlock caveats that apply to start/stop/restart do not apply. main.ts's SIGUSR2 handler is unchanged; only the delivery mechanism is fixed. Adds a static regression test over the shipped rule files.
andrescera
force-pushed
the
fix/udev-sigusr2-scoped-kill
branch
from
July 16, 2026 23:17
ff2bcdd to
0831743
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The two USB/audio hotplug udev rules now deliver
SIGUSR2to the CeraUI backend via a unit-scopedsystemctl kill, instead of a broadpkill -f:deployment/99-ceralive-check-usb-devices.rules(Elgato/Cam Link, vendor0fd9)deployment/98-ceralive-audio.rules(the singleRUN+=underLABEL="signal_ceralive", reached by all 5GOTObranches + theusbaudiofall-through)main.ts'sSIGUSR2handler is unchanged — only the delivery mechanism is fixed.Why
pkill -f ceralivesubstring-matches the full command line of every process. Once avahi registers a hostname it renames its process title toavahi-daemon: registering [<hostname>.local]; this device's hostname isceralive.local, so avahi-daemon's title containsceraliveand was caught by the same broad pkill.SIGUSR2's default disposition is terminate, andavahi-daemon.servicehas noRestart=, so mDNS (ceralive.localresolution) stayed dead until reboot — the "mDNS keeps dying" complaint.Confirmed live on real hardware via
journalctl— both the backend (PID 544) and avahi-daemon (PID 453) receivedSIGUSR2at the same udev event:systemctl killtargets the unit's cgroup — zero substring ambiguity — the same idiom already used byceralive-addon-reconciler.service.--kill-whom=mainscopes the signal to the tracked MainPID, preserving the oldpkill -osingle-process intent. This matters:srtla_send/bcrptare spawned by the backend and shareceralive.service's cgroup while streaming, and neither handlesSIGUSR2— so the whole-cgroup default (all) would terminate the active stream on every hotplug.systemctl killis safe from a udevRUN+=rule: it sends the signal via a synchronous PID-1 D-Bus call and creates no systemd job, so the--no-block/deadlock caveats that apply tostart/stop/restartdo not apply.How to verify
cd apps/backend && bun test src/tests/udev-rules-sigusr2-scope.test.ts— new static regression guard (4 tests) over the shipped rule files: nopkill -f ceraliveremains, both rules carry the scopedsystemctl kill --kill-whom=main --signal=SIGUSR2 ceralive.serviceidiom, and every audio-ruleGOTOpath converges on the single scopedRUN+=.cd apps/backend && bun tsc --noEmit— clean.biome check— clean on changed files.systemctl is-active avahi-daemon) andceralive.localstill resolves, while the backend still re-scans devices.Risks
SIGUSR2is delivered; the handler and the hotplug re-scan behavior are unchanged.--kill-whom=mainrequires systemd >= 252 (Debian bookworm floor); the device already relies on modernsystemctl(ceralive-addon-reconciler.service).Restart=on-failureonavahi-daemon.service) is handled separately inimage-building-pipelineas defense-in-depth.