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
|
#!/bin/bash
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# ── Clean up stale sockets from previous run ──────────────────────────────────
|
# ── Clean up stale sockets from previous run ──────────────────────────────────
|
||||||
rm -f /tmp/.X99-lock
|
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.
|
# gst_agent exits with code 1 on ICE failure or other fatal errors.
|
||||||
# Without a restart loop, the container sits dead until manually restarted.
|
# Without a restart loop, the container sits dead until manually restarted.
|
||||||
# 3 second delay before each restart to avoid a tight crash loop.
|
# 3 second delay before each restart to avoid a tight crash loop.
|
||||||
|
#
|
||||||
while true; do
|
while true; do
|
||||||
python3 ~/streaming-agent/gst_agent.py
|
python3 ~/streaming-agent/gst_agent.py
|
||||||
echo "[gst_agent] exited with code $?, restarting in 3s..."
|
echo "[gst_agent] exited with code $?, restarting in 3s..."
|
||||||
|
|||||||
@ -252,17 +252,6 @@ function performCssRestart(reason) {
|
|||||||
containerRestarting = true;
|
containerRestarting = true;
|
||||||
broadcastQueueState();
|
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 {
|
try {
|
||||||
execSync(`docker exec ${CONTAINER} bash -c "wineserver -k; timeout 15 wineserver -w || true"`);
|
execSync(`docker exec ${CONTAINER} bash -c "wineserver -k; timeout 15 wineserver -w || true"`);
|
||||||
console.log('[sig] CSS restart: wineserver fully torn down');
|
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.
|
// the actual cause of "keyboard stuck, mouse/video fine" after restarts.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
try {
|
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');
|
console.log('[sig] CSS restart: focused new window');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[sig] CSS restart: failed to focus new window:', e.message);
|
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
|
const CSS_RESTART_INTERVAL = 5 * 60 * 60 * 1000; // 5 hours
|
||||||
setInterval(() => performCssRestart('scheduled 5-hour restart'), CSS_RESTART_INTERVAL);
|
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) {
|
function releaseControl(entry, reason) {
|
||||||
if (idleTimer) { clearTimeout(idleTimer); idleTimer = null; }
|
if (idleTimer) { clearTimeout(idleTimer); idleTimer = null; }
|
||||||
if (currentController !== entry) return;
|
if (currentController !== entry) return;
|
||||||
@ -441,6 +480,18 @@ wss.on('connection', (ws, req) => {
|
|||||||
agentWs: ws,
|
agentWs: ws,
|
||||||
});
|
});
|
||||||
console.log(`[sig] agent registered — sessionId=${agentSessionId}`);
|
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') {
|
else if (msg.type === 'request_control') {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user