fix(rdesign): auto-restart Scribus when runner socket is missing

The bridge's /start endpoint was returning "already running" even when
the runner script had crashed (socket gone). Now kills zombie Scribus
and restarts. Agent route also verifies runner connectivity after start.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-24 11:41:58 -07:00
parent af446938be
commit e5466491c7
2 changed files with 26 additions and 3 deletions

View File

@ -96,7 +96,12 @@ def start_scribus():
global _scribus_proc global _scribus_proc
if _scribus_proc and _scribus_proc.poll() is None: if _scribus_proc and _scribus_proc.poll() is None:
if os.path.exists(SOCKET_PATH):
return jsonify({"ok": True, "message": "Scribus already running", "pid": _scribus_proc.pid}) return jsonify({"ok": True, "message": "Scribus already running", "pid": _scribus_proc.pid})
# Process alive but runner socket missing — kill and restart
_scribus_proc.kill()
_scribus_proc.wait(timeout=5)
_scribus_proc = None
# Clean up stale socket # Clean up stale socket
if os.path.exists(SOCKET_PATH): if os.path.exists(SOCKET_PATH):

View File

@ -61,7 +61,7 @@ async function bridgeState(): Promise<any> {
} }
} }
/** Start Scribus if not running. */ /** Start Scribus if not running, verify runner is connected. */
async function ensureScribusRunning(): Promise<any> { async function ensureScribusRunning(): Promise<any> {
const headers: Record<string, string> = { "Content-Type": "application/json" }; const headers: Record<string, string> = { "Content-Type": "application/json" };
if (BRIDGE_SECRET) headers["X-Bridge-Secret"] = BRIDGE_SECRET; if (BRIDGE_SECRET) headers["X-Bridge-Secret"] = BRIDGE_SECRET;
@ -72,7 +72,25 @@ async function ensureScribusRunning(): Promise<any> {
headers, headers,
signal: AbortSignal.timeout(20_000), signal: AbortSignal.timeout(20_000),
}); });
return await res.json(); const result = await res.json();
if (result.error) return result;
// Verify runner is actually connected by checking state
const stateRes = await fetch(`${SCRIBUS_BRIDGE_URL}/api/scribus/state`, {
headers,
signal: AbortSignal.timeout(10_000),
});
const state = await stateRes.json();
if (!state.error) return result;
// Runner not connected — force restart by calling start again
// (server.py now kills zombie Scribus when socket is missing)
const retryRes = await fetch(`${SCRIBUS_BRIDGE_URL}/api/scribus/start`, {
method: "POST",
headers,
signal: AbortSignal.timeout(20_000),
});
return await retryRes.json();
} catch (e: any) { } catch (e: any) {
return { error: `Bridge unreachable: ${e.message}` }; return { error: `Bridge unreachable: ${e.message}` };
} }