mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-17 18:25:42 +02:00
[eric] apps: the ghost reaper matches workspace paths case-insensitively, so a packaged app's openswarm vs OpenSwarm casing no longer spares orphans
This commit is contained in:
@@ -64,7 +64,10 @@ def find_ghost_runtime_pids() -> List[int]:
|
||||
then filtered by walking each candidate's ancestry: if a live backend is anywhere above it, it is
|
||||
someone's working app and is left alone.
|
||||
"""
|
||||
needle = os.path.abspath(WORKSPACE_DIR)
|
||||
# Case-FOLDED needle. macOS's default filesystem is case-insensitive, so a process may report
|
||||
# `.../openswarm/...` while our resolved path is `.../OpenSwarm/...`: the same folder, but a
|
||||
# case-sensitive `in` check misses it and the ghost survives (found live on a packaged smoke).
|
||||
needle = os.path.abspath(WORKSPACE_DIR).casefold()
|
||||
try:
|
||||
out = subprocess.run(["ps", "-eo", "pid=,args="], capture_output=True, text=True, timeout=8)
|
||||
except Exception:
|
||||
@@ -80,7 +83,7 @@ def find_ghost_runtime_pids() -> List[int]:
|
||||
ghosts: List[int] = []
|
||||
for line in (out.stdout or "").splitlines():
|
||||
line = line.strip()
|
||||
if needle not in line:
|
||||
if needle not in line.casefold():
|
||||
continue
|
||||
head = line.split(None, 1)
|
||||
if not head or not head[0].isdigit():
|
||||
|
||||
@@ -118,3 +118,18 @@ def test_indeterminate_ancestry_is_never_a_ghost(monkeypatch):
|
||||
ghosts = rg.find_ghost_runtime_pids()
|
||||
assert 999 not in ghosts, "pid absent from the ppid map was treated as a ghost"
|
||||
assert ghosts == [300], "a genuinely orphaned pid (walks to init, no backend) still reaps"
|
||||
|
||||
|
||||
def test_ghost_matched_despite_path_case_difference(monkeypatch):
|
||||
"""macOS is case-insensitive, so a process can report .../openswarm/... while our resolved path
|
||||
is .../OpenSwarm/... (same folder). A case-sensitive match missed the ghost entirely; found live
|
||||
on a packaged smoke where 8 orphans survived a reap that logged 0."""
|
||||
from backend.apps.outputs import reap_ghost_runtimes as rg
|
||||
ws = rg.os.path.abspath(rg.WORKSPACE_DIR)
|
||||
lower_ws = ws.replace("OpenSwarm", "openswarm").replace("Openswarm", "openswarm")
|
||||
monkeypatch.setattr(rg, "p_live_backend_pids", lambda: {50})
|
||||
monkeypatch.setattr(rg, "p_ppid_map", lambda: {700: 1}) # orphan reparented to init
|
||||
class P_Out:
|
||||
stdout = f"50 python -m uvicorn backend.main:app\n700 bash {lower_ws}/ws-x/backend/run.sh\n"
|
||||
monkeypatch.setattr(rg.subprocess, "run", lambda *a, **k: P_Out())
|
||||
assert rg.find_ghost_runtime_pids() == [700], "a case-different path must still match the ghost"
|
||||
|
||||
Reference in New Issue
Block a user