livekit-graceful-restart.sh is supposed to restart LiveKit only when no call is active. Its check could never see a call.
Bugs
ss -tn state established '(…)' | grep -c ESTAB is always 0. With a state filter, ss omits the State column, so there's no "ESTAB" to grep.
It counted connections on :7881, which is only LiveKit's ICE-TCP media fallback. Signalling is on :7880, and media is normally UDP.
The deploy hook never installed this script when it changed, so fixes to it never reached LXC 151.
It hasn't caused an outage only because nothing has staged a LiveKit restart in the retained logs. The upcoming LiveKit 1.9 → 1.13 upgrade would be its first real use.
Fix
Wait while LiveKit's own livekit_participant_total (from :6789/metrics) is above 0, or any signalling WebSocket on :7880 is open (ss -H … | wc -l).
If the metrics can't be read, assume a call is active and wait.
deploy/lxc151-hookshot.sh installs the script to /usr/local/bin when it changes, after a bash -n syntax check.
`livekit-graceful-restart.sh` is supposed to restart LiveKit only when no call is active. Its check could never see a call.
## Bugs
1. `ss -tn state established '(…)' | grep -c ESTAB` is **always 0**. With a `state` filter, `ss` omits the State column, so there's no "ESTAB" to grep.
2. It counted connections on **:7881**, which is only LiveKit's ICE-TCP media fallback. Signalling is on **:7880**, and media is normally UDP.
3. The deploy hook never installed this script when it changed, so fixes to it never reached LXC 151.
It hasn't caused an outage only because nothing has staged a LiveKit restart in the retained logs. The upcoming LiveKit 1.9 → 1.13 upgrade would be its first real use.
## Fix
- Wait while LiveKit's own `livekit_participant_total` (from `:6789/metrics`) is above 0, **or** any signalling WebSocket on :7880 is open (`ss -H … | wc -l`).
- If the metrics can't be read, assume a call is active and wait.
- `deploy/lxc151-hookshot.sh` installs the script to `/usr/local/bin` when it changes, after a `bash -n` syntax check.
## Tested
Local stack, with `systemctl` stubbed out:
| Case | Old check | New check |
|---|---|---|
| two-person call | 0 connections → **restart** | 2 participants, 3 signalling → wait |
| metrics unreachable | — | wait |
| idle | restart | restart |
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
livekit-graceful-restart.sh decided "no active calls" by counting
established TCP connections on :7881 with `ss ... state established |
grep -c ESTAB`. Two bugs:
- With a `state` filter ss omits the State column, so `grep -c ESTAB`
is always 0: the check never saw anything.
- :7881 is only LiveKit's ICE-TCP media fallback. Signalling is on
:7880 and media is normally UDP.
Reproduced in a two-person call on the local stack: the old check
counted 0 and would have restarted. Now it waits while LiveKit's own
livekit_participant_total is above 0 or any signalling WebSocket on
:7880 is open, and also waits if the metrics can't be read.
The deploy hook now installs the script when it changes (it never
did, so edits to it never reached the server).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
jared
scheduled this pull request to auto merge when all checks succeed 2026-11-03 00:26:21 -05:00
jared
merged commit 8a0e16cabd into main2026-11-03 00:28:12 -05:00
jared
deleted branch fix/livekit-graceful-restart-detection2026-11-03 00:28:13 -05:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
livekit-graceful-restart.shis supposed to restart LiveKit only when no call is active. Its check could never see a call.Bugs
ss -tn state established '(…)' | grep -c ESTABis always 0. With astatefilter,ssomits the State column, so there's no "ESTAB" to grep.It hasn't caused an outage only because nothing has staged a LiveKit restart in the retained logs. The upcoming LiveKit 1.9 → 1.13 upgrade would be its first real use.
Fix
livekit_participant_total(from:6789/metrics) is above 0, or any signalling WebSocket on :7880 is open (ss -H … | wc -l).deploy/lxc151-hookshot.shinstalls the script to/usr/local/binwhen it changes, after abash -nsyntax check.Tested
Local stack, with
systemctlstubbed out:🤖 Generated with Claude Code
https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5