[eric] outputs: a restart that binds clears the previous bind-timeout verdict instead of reporting boot_failed forever

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012G8kyALnPjsA7aJFmMBq3R
This commit is contained in:
ciregenz
2026-09-02 08:25:54 -07:00
co-authored by Claude Fable 5.1
parent 8acfe2c15e
commit f7472a36af
2 changed files with 38 additions and 0 deletions
+2
View File
@@ -231,6 +231,8 @@ class AppRuntime:
self.p_reset_terminal_log()
# Every boot re-decides serve mode from scratch; a stale True from the previous boot would make ready/frontend_url claim a processless app is fine after a restart that exists to spawn one.
self.serve_static = False
# Same for the bind-timeout verdict: a restart that then binds fine must not keep telling the card the boot failed.
self.boot_failed = False
if self.is_new_mode:
# Acquire the module-level boot lock BEFORE the spawn so only one new-mode workspace is mid-bundle at a time. The lock is released by the bind-poll task the moment vite emits "frontend ready" (or its 180s timeout fires), which is the moment the next workspace can start its own vite without competing for the same CPU. See `p_await_frontend_bind` for the release.
p_boot_lock = get_vite_boot_lock()
@@ -0,0 +1,36 @@
"""A bind timeout stamps boot_failed so the card stops spinning, but the flag lived on the runtime
object forever: after one 180s timeout every later restart of the same runtime kept reporting
boot_failed=True even while ready=True (seen live on an app card, 2026-09-02). start() now clears it."""
import pytest
from backend.apps.outputs.runtime import AppRuntime
def p_rt(tmp_path) -> AppRuntime:
ws = tmp_path / "ws"
ws.mkdir(exist_ok=True)
(ws / "run.sh").write_text("#!/bin/bash\n")
return AppRuntime(workspace_id="ws-boot-failed", workspace_path=str(ws))
@pytest.mark.asyncio
async def test_a_restart_that_boots_clears_the_previous_bind_timeout(tmp_path, monkeypatch):
rt = p_rt(tmp_path)
rt.boot_failed = True
async def p_fake_spawn() -> bool:
return True
monkeypatch.setattr(rt, "p_start_new_mode", p_fake_spawn)
assert await rt.start() is True
assert rt.boot_failed is False, "a boot that spawned fine must not keep telling the card the previous one failed"
@pytest.mark.asyncio
async def test_an_already_running_runtime_keeps_its_verdict(tmp_path, monkeypatch):
rt = p_rt(tmp_path)
rt.boot_failed = True
monkeypatch.setattr(type(rt), "running", property(lambda self: True))
assert await rt.start() is True
assert rt.boot_failed is True, "start() on a live runtime is a no-op and must not rewrite state"