fix(memory): avoid setup autostart for unhealthy OpenViking

This commit is contained in:
Hao Zhe 2026-06-17 01:32:43 +08:00
parent 315fdae5f8
commit 166d2457b2
2 changed files with 64 additions and 4 deletions

View file

@ -89,6 +89,7 @@ _MEMORY_WRITE_TARGET_SUBDIR_MAP = {
_LOCAL_OPENVIKING_HOSTS = {"localhost", "127.0.0.1", "::1"}
_LOCAL_OPENVIKING_AUTOSTART_TIMEOUT = 60.0
_OPENVIKING_SERVER_LOG_RELATIVE_PATH = Path("logs") / "openviking-server.log"
_OPENVIKING_RESPONDED_FAILURE_PREFIX = "OpenViking server responded"
_SETUP_CANCELLED = object()
@ -806,6 +807,8 @@ def _validate_openviking_reachability(endpoint: str) -> tuple[bool, str]:
elif client.health():
return True, ""
except Exception as e:
if _status_code_from_error(e) is not None:
return False, f"OpenViking server responded with {_format_openviking_exception(e)}."
return False, f"OpenViking server is not reachable at {endpoint}: {_format_openviking_exception(e)}"
return False, f"OpenViking server is not reachable at {endpoint}."
@ -984,8 +987,19 @@ def _wait_for_openviking_health(endpoint: str, *, timeout_seconds: float = 15.0)
return False
def _handle_unreachable_endpoint(endpoint: str, message: str, select, cancelled):
if _is_local_openviking_url(endpoint):
def _reachability_failure_allows_local_autostart(message: str) -> bool:
return not (message or "").startswith(_OPENVIKING_RESPONDED_FAILURE_PREFIX)
def _handle_unreachable_endpoint(
endpoint: str,
message: str,
select,
cancelled,
*,
allow_local_autostart: bool = True,
):
if _is_local_openviking_url(endpoint) and allow_local_autostart:
print(f" {message}")
choice = select(
" Local OpenViking server is down",
@ -1017,7 +1031,7 @@ def _handle_unreachable_endpoint(endpoint: str, message: str, select, cancelled)
return _retry_or_cancel_manual_setup(
select,
" OpenViking server unreachable",
" OpenViking server unhealthy" if _is_local_openviking_url(endpoint) else " OpenViking server unreachable",
message,
cancelled,
)
@ -1126,7 +1140,13 @@ def _prompt_manual_connection_values(prompt, select, cancelled, *, service: bool
if reachable:
print(" OpenViking server is reachable.")
break
retry = _handle_unreachable_endpoint(endpoint, message, select, cancelled)
retry = _handle_unreachable_endpoint(
endpoint,
message,
select,
cancelled,
allow_local_autostart=_reachability_failure_allows_local_autostart(message),
)
if retry is True:
break
if retry is _SETUP_CANCELLED:

View file

@ -779,6 +779,46 @@ def test_handle_unreachable_endpoint_waits_long_enough_after_autostart(monkeypat
assert "Waiting for OpenViking server to become reachable..." in output
def test_manual_setup_does_not_offer_autostart_when_local_server_is_unhealthy(monkeypatch):
_clear_openviking_env(monkeypatch)
class FakeVikingClient:
def __init__(self, endpoint, api_key="", account="", user="", agent=""):
assert endpoint == "http://localhost:1933"
def health_payload(self):
return {"healthy": False}
select_calls = []
def select(title, options, **kwargs):
select_calls.append((title, options))
assert all(label != "Start local OpenViking" for label, _description in options)
return 1
monkeypatch.setattr(openviking_module, "_VikingClient", FakeVikingClient)
monkeypatch.setattr(
openviking_module,
"_start_local_openviking_server",
MagicMock(side_effect=AssertionError("unhealthy local server should not offer auto-start")),
)
result = openviking_module._prompt_manual_connection_values(
_prompt_from_values({"OpenViking server URL": "localhost"}),
select,
-1,
)
assert result is openviking_module._SETUP_CANCELLED
assert select_calls == [(
" OpenViking server unhealthy",
[
("Retry", "try this step again"),
("Cancel setup", "no changes saved"),
],
)]
def test_initialize_autostarts_local_openviking_in_background_when_runtime_health_fails(monkeypatch):
_clear_openviking_env(monkeypatch)
monkeypatch.setenv("OPENVIKING_ENDPOINT", "http://127.0.0.1:1934")