Skip to content

fix(visaged): handle SIGTERM (closes #26)#30

Merged
ccross2 merged 2 commits into
mainfrom
fix/issue-26-sigterm-handler
May 28, 2026
Merged

fix(visaged): handle SIGTERM (closes #26)#30
ccross2 merged 2 commits into
mainfrom
fix/issue-26-sigterm-handler

Conversation

@ccross2
Copy link
Copy Markdown
Contributor

@ccross2 ccross2 commented May 28, 2026

Summary

Closes #26systemctl restart visaged.service hangs for ~90s after hibernate resume because visaged ignores SIGTERM.

Root cause

crates/visaged/src/main.rs:91 used tokio::signal::ctrl_c().await? for shutdown. On Unix, tokio::signal::ctrl_c() is SIGINT-only. systemd's systemctl stop / systemctl restart sends SIGTERM, which the daemon has no handler for — so systemd waits the default TimeoutStopSec=90s before escalating to SIGKILL. Reported as the ~90s window during which face auth doesn't work after visage-resume.service fires.

Note: this is independent of the stale-camera-fd concern in the original report. The fd may indeed go bad across hibernate, but the user-visible 90s hang is entirely on the signal-handling side — we never reach any shutdown / fd-teardown path.

Fix

Two changes:

  1. crates/visaged/src/main.rs — install handlers for both SIGINT and SIGTERM via tokio::signal::unix::signal(SignalKind::terminate()) + SignalKind::interrupt(), awaited in a tokio::select!. Matches the pattern used in our other daemons (e.g. esver-capture-cli's wait_for_shutdown_signal).
  2. packaging/systemd/visaged.service — add TimeoutStopSec=10s as defense in depth, in case a v4l2 capture is mid-flight and not promptly interruptible (e.g. a stale camera fd on hibernate resume that the v4l ioctl can't immediately abort).

Verification

  • Mechanical correctness: the engine task is parked on rx.blocking_recv() (crates/visaged/src/engine.rs:166); when main returns and the tokio runtime drops, the channel sender drops, the engine thread exits cleanly. No new shutdown plumbing required.
  • Worst-case systemctl restart goes from ~90s → ~10s for the rare case where the capture loop genuinely can't unwind in time.
  • Local cargo check blocked on a devshell gap (missing libclang for v4l2-sys bindgen, missing rustfmt/clippy) — CI will run all gates. I'll file a separate PR to round out the devshell.

Test plan

  • CI: cargo fmt --all -- --check clean
  • CI: cargo clippy --workspace -- -D warnings clean
  • CI: cargo test --workspace green
  • CI: build-deb produces a .deb cleanly
  • Manual on a hibernate-capable system (Surface / ThinkPad pre-Gen11 / EliteBook / Zenbook 14):
    • sudo systemctl restart visaged.service returns in ~1s when idle (was ~1s before, should still be ~1s — sanity check)
    • sudo systemctl restart visaged.service returns in ≤10s after hibernate resume (previously ~90s)
    • Face auth resumes working without further intervention

CHANGELOG

Entry added under [Unreleased] > Fixed. Will land in v0.3.2 per the release plan.

🤖 Generated with Claude Code

`tokio::signal::ctrl_c()` is SIGINT-only on Unix. systemd's `systemctl
stop`/`systemctl restart` sends SIGTERM, which visaged was ignoring —
systemd then waited the default `TimeoutStopSec=90s` before escalating
to SIGKILL, manifesting as the ~90s hang reported in issue #26 after
`visage-resume.service` restarts the daemon post-hibernate.

Install handlers for both SIGINT and SIGTERM via
`tokio::signal::unix::signal` and `tokio::select!`, matching the pattern
used elsewhere in our daemons (e.g. `esver-capture-cli`).

Also adds `TimeoutStopSec=10s` to `visaged.service` as defense in depth
for the edge case where a v4l2 capture is mid-flight on shutdown — for
example a stale camera fd after hibernate resume that isn't promptly
interruptible. Brings the worst-case `systemctl restart` from ~90s to
~10s instead of the prior default-90s SIGKILL escalation.

CHANGELOG entry added under `[Unreleased] > Fixed`.
CI flagged the prior commit's binding shape. rustfmt prefers the binding
name on its own line when the value-expression spans the column budget.
No semantic change.
@ccross2 ccross2 merged commit fc2d7f9 into main May 28, 2026
3 checks passed
@ccross2 ccross2 mentioned this pull request May 28, 2026
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

visaged: blocks for 90s on systemctl restart after hibernate due to stale camera fd

1 participant