mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
fix(cli): fall back gracefully when embedding-server sidecar is absent (#1206)
## Description `headroom proxy --embedding-server` crashes at startup with `ModuleNotFoundError: No module named 'headroom.memory.adapters.watchdog'` instead of falling back to the per-worker embedder. The `EmbeddingServerWatchdog` import sits above the `try/except` that is meant to catch sidecar-startup failures, so a missing sidecar module raises before the guard runs and takes the whole proxy down. The sidecar module is not present on main (it ships with the dedicated embedding-server sidecar work). ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Move the `EmbeddingServerWatchdog` import into the guarded `_start_embed_watchdog` coroutine in `headroom/cli/proxy.py`, so a missing sidecar module is caught by the existing `try/except` and the proxy degrades to the per-worker embedder. - Add `tests/test_cli_proxy_embedding_server.py`, a regression test that forces the sidecar module unimportable and asserts the flag falls back instead of crashing. ## Testing - [ ] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text # The new regression test was validated fail-before / pass-after against the released # build via click's CliRunner (forces the sidecar module unimportable, stubs run_server): # before fix (parent commit): exit_code 1, ModuleNotFoundError, no fallback message # after fix: exit_code 0, no exception, "Falling back to per-worker embedder" # ruff check . and ruff format --check . pass locally on the rebased branch. # Full pytest suite / mypy not run locally; left to CI. ``` ## Real Behavior Proof - Environment: released build (headroom 0.26.0), Linux - Exact command / steps: `headroom proxy --embedding-server --port 8799` - Observed result: the proxy no longer crashes. Before the fix it exits immediately with `ModuleNotFoundError: No module named 'headroom.memory.adapters.watchdog'`; after the fix it logs `WARNING: Failed to start embedding server sidecar: No module named 'headroom.memory.adapters.watchdog'. Falling back to per-worker embedder.`, then prints `URL: http://127.0.0.1:8799` and `Optimization: ENABLED` and serves normally. - Not tested: full pytest suite and mypy locally (left to CI) ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable --------- Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
This commit is contained in:
parent
3ccdad6c67
commit
38f1404432
2 changed files with 37 additions and 2 deletions
|
|
@ -1273,9 +1273,13 @@ Press Ctrl+C to stop.
|
|||
|
||||
import asyncio as _asyncio
|
||||
|
||||
from headroom.memory.adapters.watchdog import EmbeddingServerWatchdog
|
||||
|
||||
async def _start_embed_watchdog() -> Any:
|
||||
# Import lazily inside the guarded coroutine. The sidecar module is
|
||||
# optional and may be absent; keeping the import here lets the
|
||||
# try/except below fall back to the per-worker embedder instead of
|
||||
# crashing the proxy at startup with ModuleNotFoundError.
|
||||
from headroom.memory.adapters.watchdog import EmbeddingServerWatchdog
|
||||
|
||||
wd = EmbeddingServerWatchdog(socket_path=_embed_socket)
|
||||
await wd.start()
|
||||
ok = await wd.wait_until_healthy(timeout=30.0)
|
||||
|
|
|
|||
31
tests/test_cli_proxy_embedding_server.py
Normal file
31
tests/test_cli_proxy_embedding_server.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
"""Regression test for `proxy --embedding-server` startup fallback.
|
||||
|
||||
The optional embedding-server sidecar module
|
||||
(`headroom.memory.adapters.watchdog`) is not present on main, yet the
|
||||
`--embedding-server` flag advertises a graceful fallback to the per-worker
|
||||
embedder. A misplaced import made the flag raise ``ModuleNotFoundError`` at
|
||||
startup and crash the proxy instead of falling back.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from click.testing import CliRunner
|
||||
|
||||
from headroom.cli import main
|
||||
|
||||
|
||||
def test_embedding_server_missing_sidecar_falls_back(monkeypatch):
|
||||
# Make the optional sidecar module unimportable regardless of whether it is
|
||||
# installed, so the fallback path is exercised deterministically.
|
||||
monkeypatch.setitem(sys.modules, "headroom.memory.adapters.watchdog", None)
|
||||
|
||||
# Don't actually start a server.
|
||||
import headroom.proxy.server as server_mod
|
||||
|
||||
monkeypatch.setattr(server_mod, "run_server", lambda *args, **kwargs: None)
|
||||
|
||||
result = CliRunner().invoke(main, ["proxy", "--embedding-server", "--port", "8799"])
|
||||
|
||||
assert result.exit_code == 0, f"proxy crashed instead of falling back: {result.output}"
|
||||
assert result.exception is None
|
||||
assert "Falling back to per-worker embedder" in result.output
|
||||
Loading…
Add table
Add a link
Reference in a new issue