removed set -euo pipefail and added auto container restarting to signaling server
This commit is contained in:
parent
9755e2ccf5
commit
b84c728470
2
start.sh
2
start.sh
@ -1,5 +1,4 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# ── Clean up stale sockets from previous run ──────────────────────────────────
|
||||
rm -f /tmp/.X99-lock
|
||||
@ -117,6 +116,7 @@ echo "socat mic listener started on TCP :12345"
|
||||
# gst_agent exits with code 1 on ICE failure or other fatal errors.
|
||||
# Without a restart loop, the container sits dead until manually restarted.
|
||||
# 3 second delay before each restart to avoid a tight crash loop.
|
||||
#
|
||||
while true; do
|
||||
python3 ~/streaming-agent/gst_agent.py
|
||||
echo "[gst_agent] exited with code $?, restarting in 3s..."
|
||||
|
||||
@ -252,17 +252,6 @@ function performCssRestart(reason) {
|
||||
containerRestarting = true;
|
||||
broadcastQueueState();
|
||||
|
||||
// Use Wine's own proper teardown instead of pkill + a fixed sleep guess.
|
||||
// `wineserver -k` signals every Wine process under this prefix to exit;
|
||||
// `wineserver -w` BLOCKS until wineserver has actually fully released all
|
||||
// its shared memory / locks / sockets, rather than gambling on a fixed
|
||||
// delay being long enough. This is what previously let a fresh CSS
|
||||
// instance start before the old one had genuinely finished tearing down,
|
||||
// inheriting a wedged state and landing right back on the same stuck
|
||||
// "Connecting to server..." screen even after repeated restarts.
|
||||
// Wrapped in `timeout` so a manual restart can never hang indefinitely if
|
||||
// wineserver somehow never exits — after 15s we give up waiting and
|
||||
// proceed to relaunch anyway.
|
||||
try {
|
||||
execSync(`docker exec ${CONTAINER} bash -c "wineserver -k; timeout 15 wineserver -w || true"`);
|
||||
console.log('[sig] CSS restart: wineserver fully torn down');
|
||||
@ -296,7 +285,14 @@ function performCssRestart(reason) {
|
||||
// the actual cause of "keyboard stuck, mouse/video fine" after restarts.
|
||||
setTimeout(() => {
|
||||
try {
|
||||
execSync(`docker exec ${CONTAINER} bash -c "DISPLAY=:99 WIN=\$(xdotool search --name '' | head -1) && xdotool windowfocus --sync \$WIN" || true`);
|
||||
// A fresh `docker exec` session gets a NEW environment built from
|
||||
// the image's defaults, not the runtime environment of the
|
||||
// container's PID 1 (start.sh) — unlike gst_agent.py, which
|
||||
// inherits start.sh's environment directly as a child process and
|
||||
// has always found xdotool fine. Explicitly ensure common binary
|
||||
// paths are present here too, since this exact command was
|
||||
// silently failing with "xdotool: not found" every time.
|
||||
execSync(`docker exec ${CONTAINER} bash -c "export PATH=\$PATH:/usr/bin:/usr/local/bin:/bin; DISPLAY=:99 WIN=\$(xdotool search --name '' | head -1) && xdotool windowfocus --sync \$WIN" || true`);
|
||||
console.log('[sig] CSS restart: focused new window');
|
||||
} catch (e) {
|
||||
console.error('[sig] CSS restart: failed to focus new window:', e.message);
|
||||
@ -313,6 +309,49 @@ function performCssRestart(reason) {
|
||||
const CSS_RESTART_INTERVAL = 5 * 60 * 60 * 1000; // 5 hours
|
||||
setInterval(() => performCssRestart('scheduled 5-hour restart'), CSS_RESTART_INTERVAL);
|
||||
|
||||
// ── Container liveness check ──────────────────────────────────────────────────
|
||||
// Everything above (performCssRestart, the watchdog, the manual restart
|
||||
// button) assumes the DOCKER CONTAINER itself is alive and only needs its
|
||||
// internal Wine/CSS process cycled. If the container's own main process
|
||||
// (start.sh, PID 1) dies for any reason, the whole container exits — at
|
||||
// which point every docker exec call above fails outright with "container
|
||||
// is not running",
|
||||
//
|
||||
const CONTAINER_LIVENESS_INTERVAL = 30 * 1000; // 30 seconds
|
||||
|
||||
function checkContainerLiveness() {
|
||||
let running = false;
|
||||
try {
|
||||
const out = execSync(`docker inspect -f "{{.State.Running}}" ${CONTAINER}`).toString().trim();
|
||||
running = out === 'true';
|
||||
} catch (e) {
|
||||
running = false;
|
||||
}
|
||||
|
||||
if (!running) {
|
||||
console.error(`[sig] CONTAINER ${CONTAINER} IS NOT RUNNING — attempting docker start`);
|
||||
try {
|
||||
execSync(`docker start ${CONTAINER}`);
|
||||
console.log(`[sig] docker start ${CONTAINER} succeeded — container should reboot via start.sh`);
|
||||
} catch (e) {
|
||||
console.error(`[sig] docker start ${CONTAINER} failed:`, e.message);
|
||||
}
|
||||
|
||||
// The old agent registration and controller state are now stale — the
|
||||
// container is rebooting from scratch (fresh gst_agent, fresh CSS).
|
||||
// Clear them so the browser doesn't sit on a dead session waiting for
|
||||
// an agent that will never re-register under the old WebSocket.
|
||||
agentSessions.clear();
|
||||
if (currentController) {
|
||||
releaseControl(currentController, 'container-restart');
|
||||
}
|
||||
containerRestarting = true;
|
||||
broadcastQueueState();
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(checkContainerLiveness, CONTAINER_LIVENESS_INTERVAL);
|
||||
|
||||
function releaseControl(entry, reason) {
|
||||
if (idleTimer) { clearTimeout(idleTimer); idleTimer = null; }
|
||||
if (currentController !== entry) return;
|
||||
@ -441,6 +480,18 @@ wss.on('connection', (ws, req) => {
|
||||
agentWs: ws,
|
||||
});
|
||||
console.log(`[sig] agent registered — sessionId=${agentSessionId}`);
|
||||
|
||||
// A fresh agent registering is the actual completion signal for a
|
||||
// full container reboot (checkContainerLiveness sets
|
||||
// containerRestarting=true immediately after `docker start`, but that
|
||||
// only kicks off the boot — the full start.sh sequence, Weston,
|
||||
// Xwayland, PipeWire, CSS launch, then gst_agent itself starting and
|
||||
// registering, takes much longer than a same-container CSS restart).
|
||||
// Clear it here so the browser's loading overlay doesn't stay stuck.
|
||||
if (containerRestarting) {
|
||||
containerRestarting = false;
|
||||
broadcastQueueState();
|
||||
}
|
||||
}
|
||||
|
||||
else if (msg.type === 'request_control') {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user