mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-10 14:27:00 -04:00
## 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>
31 lines
1.2 KiB
Python
31 lines
1.2 KiB
Python
"""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
|