[eric] router: adopt a healthy 9Router instead of evicting the one other backends are using

This commit is contained in:
ciregenz
2026-08-03 16:44:18 -07:00
parent a6e63815e7
commit cc2f463443
2 changed files with 44 additions and 1 deletions
+13 -1
View File
@@ -497,7 +497,19 @@ async def p_ensure_running_impl():
p_is_packaged = os.environ.get("OPENSWARM_PACKAGED") == "1"
if is_running():
# In dev mode, kill stale standalone servers (from previous builds) so we can start `next dev` which always uses latest source code
# ADOPT a healthy router instead of evicting it. is_running() has just confirmed HTTP 200 on
# /v1/models, so whatever is on the port is serving; the only thing killing it establishes is
# who owns the process. That eviction is a thrash engine on a shared machine: every dev
# backend that boots kills the router the others are using, their watchdogs revive it, and
# the next boot kills it again. Measured with 8 backends on one box: a coverage sweep scored
# 1/9 with zero code change, wall times went 30s -> 202s, and one run logged 0 kills of its
# own against 4 revives. The original reason to kill ("stale build") does not apply to a
# component we pin by npm version rather than build from source. OPENSWARM_ROUTER_TAKEOVER=1
# restores the old behaviour for the rare case someone must force a fresh spawn.
if not p_is_packaged and os.environ.get("OPENSWARM_ROUTER_TAKEOVER") != "1":
logger.info("9Router already healthy on port %d; adopting it (set "
"OPENSWARM_ROUTER_TAKEOVER=1 to force a fresh spawn)", NINE_ROUTER_PORT)
return
if not p_is_packaged:
# But never kill the instance WE already started: a second ensure call (another sub-app's lifespan races settings') would pkill our fresh next-server, leaving a dead window the boot key-sync fails into, so the cp-openai node never registers and gpt-5.* own-key dies.
if p_process is not None and p_process.poll() is None:
+31
View File
@@ -204,3 +204,34 @@ def test_detection_revival_gated_on_evidence():
assert ensures, "sub-only users must get a revival attempt"
asyncio.run(run())
def test_a_healthy_router_is_adopted_not_evicted():
"""The dev-machine thrash engine, removed.
Every dev backend used to kill any 9Router it had not personally spawned, on a "stale build"
rationale that does not apply to a component we pin by npm version instead of building from
source. On a shared box that is a loop: each boot evicts the router the others are using, their
watchdogs revive it, the next boot evicts it again. Measured with 8 backends on one machine, a
coverage sweep scored 1/9 with zero code change, wall times went 30s -> 202s, and one backend
logged 0 kills of its own against 4 revives.
is_running() has already confirmed HTTP 200 on /v1/models before this point, so the router is
serving by definition; killing it settles ownership and nothing else.
"""
killed = []
with patch.object(proc, "is_running", return_value=True), \
patch.object(proc, "p_process", None), \
patch("subprocess.run", side_effect=lambda *a, **k: killed.append(a)), \
patch.dict("os.environ", {"OPENSWARM_PACKAGED": "0"}, clear=False):
asyncio.run(proc.p_ensure_running_impl())
assert killed == [], "a healthy router another process owns must be adopted, never pkill'd"
def test_takeover_escape_hatch_still_exists():
"""Adoption must not become a trap: someone genuinely needing a fresh spawn keeps a way to get
one, and it is explicit rather than the silent default."""
import inspect
src = inspect.getsource(proc.p_ensure_running_impl)
assert "OPENSWARM_ROUTER_TAKEOVER" in src
assert 'os.environ.get("OPENSWARM_ROUTER_TAKEOVER") != "1"' in src