diff --git a/docs/swarmui.md b/docs/swarmui.md index 2a27f52..5697803 100644 --- a/docs/swarmui.md +++ b/docs/swarmui.md @@ -32,7 +32,7 @@ Первый запуск качает backend в `/opt/swarmui/dlbackend` (это bind на data volume). Иначе каждый recreate потеряет часы. -**gpu-rent:** после `systemctl start swarmui` вызывается headless `InstallConfirmWS` (`backend=comfyui`, `models=none`), если `GetCurrentStatus` ещё `empty`. Без этого UI отвечает HTTP 200, а Comfy/torch так и не появляются — раньше `wait_backend_idle` ошибочно считал `empty` = Idle. +**gpu-rent:** после `systemctl start swarmui` вызывается headless `InstallConfirmWS` (`backend=comfyui`, `models=none`), если `GetCurrentStatus` ещё `empty`. `IsInstalled: true` пишется только когда Comfy уже на диске; на первом старте (или если прошлый `up` оставил флаг без `dlbackend/ComfyUI`) флаг сбрасывается — иначе Swarm отвечает `Server is already installed!` и не клонирует Comfy. Без этого UI отвечает HTTP 200, а Comfy/torch так и не появляются — раньше `wait_backend_idle` ошибочно считал `empty` = Idle. **Скорость без потери качества (gpu-rent):** после Idle backend, на GPU с compute capability ≥ 8.0 и ≥16 GiB VRAM — SageAttention. `Performance.AllowGpuSpecificOptimizations` у Swarm по умолчанию уже включает `--fast` для 30xx+. Если venv ещё не появился — маркер без `pip_ok`, догонит на следующем `up`. diff --git a/src/gpu_rent/provision.py b/src/gpu_rent/provision.py index cecfb7c..5efa6d0 100644 --- a/src/gpu_rent/provision.py +++ b/src/gpu_rent/provision.py @@ -490,6 +490,9 @@ for p in uniq: continue if "/mnt/swarm_data/" not in str(p): continue + if not Path("/mnt/swarm_data").is_dir(): + print(f"skip create {p}: /mnt/swarm_data нет") + continue p.parent.mkdir(parents=True, exist_ok=True) p.write_text( "IsInstalled: true\n" diff --git a/tests/test_wait_backend_idle.py b/tests/test_wait_backend_idle.py index 7316941..eb227e2 100644 --- a/tests/test_wait_backend_idle.py +++ b/tests/test_wait_backend_idle.py @@ -48,6 +48,9 @@ def test_install_swarm_comfy_script_payload(): assert "absolute StartScript" in text or "reconfigure errored" in text assert "/mnt/swarm_data" in text or "DATA /" in text assert 'bstat in ("empty", "disabled", "all_disabled", "unknown")' in text + assert "prepare_first_install" in text + assert "already installed" in text + assert "Open SwarmUI → Server → Backends" not in text def test_wait_backend_idle_fail_fast_on_long_loading(monkeypatch): diff --git a/tests/test_warm_up_skips.py b/tests/test_warm_up_skips.py index 9c041d6..57e9bf2 100644 --- a/tests/test_warm_up_skips.py +++ b/tests/test_warm_up_skips.py @@ -102,9 +102,57 @@ def test_autocomplete_merge_sets_is_installed(): assert "IsInstalled: true" in _AUTOCOMPLETE_MERGE_PY assert "IsInstalled: true" in _ENSURE_INSTALLED_PY + assert "comfy_on_disk" in _AUTOCOMPLETE_MERGE_PY + assert "comfy_on_disk" in _ENSURE_INSTALLED_PY + assert r"\1false" in _AUTOCOMPLETE_MERGE_PY + assert r"\1false" in _ENSURE_INSTALLED_PY + assert "GPU_RENT_COMFY_PRESENT" in _AUTOCOMPLETE_MERGE_PY + assert "GPU_RENT_COMFY_PRESENT" in _ENSURE_INSTALLED_PY assert hasattr(provision, "ensure_settings_is_installed") +def test_ensure_installed_clears_flag_without_comfy(tmp_path): + import os + import re + import subprocess + import sys + + from gpu_rent.provision import _ENSURE_INSTALLED_PY + + settings = tmp_path / "Settings.fds" + settings.write_text("IsInstalled: true\nTheme: modern_dark\n", encoding="utf-8") + script = tmp_path / "ensure.py" + script.write_text(_ENSURE_INSTALLED_PY, encoding="utf-8") + env = os.environ.copy() + env["GPU_RENT_SETTINGS_FDS"] = str(settings) + env["GPU_RENT_COMFY_PRESENT"] = "0" + out = subprocess.check_output([sys.executable, str(script)], env=env, text=True) + assert "IsInstalled false" in out or "cleared" in out + text = settings.read_text(encoding="utf-8") + assert re.search(r"(?im)^\s*IsInstalled:\s*false\s*$", text) + assert "Theme: modern_dark" in text + + +def test_ensure_installed_sets_true_when_comfy_present(tmp_path): + import os + import re + import subprocess + import sys + + from gpu_rent.provision import _ENSURE_INSTALLED_PY + + settings = tmp_path / "Settings.fds" + settings.write_text("IsInstalled: false\n", encoding="utf-8") + script = tmp_path / "ensure.py" + script.write_text(_ENSURE_INSTALLED_PY, encoding="utf-8") + env = os.environ.copy() + env["GPU_RENT_SETTINGS_FDS"] = str(settings) + env["GPU_RENT_COMFY_PRESENT"] = "1" + subprocess.check_call([sys.executable, str(script)], env=env) + text = settings.read_text(encoding="utf-8") + assert re.search(r"(?im)^\s*IsInstalled:\s*true\s*$", text) + + def test_install_comfy_patches_is_installed_on_skip(): from importlib.resources import files @@ -113,3 +161,20 @@ def test_install_comfy_patches_is_installed_on_skip(): ) assert "ensure_settings_installed_flag" in text assert "leave /Install" in text + assert "prepare_first_install" in text + assert "already installed" in text + assert "IsInstalled=false" in text + assert "Open SwarmUI" not in text + + +def test_clear_settings_installed_flag(tmp_path, monkeypatch): + from gpu_rent.remote import install_swarm_comfy as inst + + settings = tmp_path / "Settings.fds" + settings.write_text("IsInstalled: true\nTheme: x\n", encoding="utf-8") + monkeypatch.setattr(inst, "SETTINGS", settings) + assert inst.clear_settings_installed_flag() is True + text = settings.read_text(encoding="utf-8") + assert "IsInstalled: false" in text + assert "Theme: x" in text + assert inst.clear_settings_installed_flag() is False