fix(embedding): make warmup best-effort so a keyless config doesn't fail startup

Eager warmup at startup constructed the embedding client unconditionally, so a deployment without an embedding API key crashed at boot instead of failing lazily on first embedding use as before. Keep failing fast on a bad tokenizer spec (ValidationException), but log and defer any other construction error.
This commit is contained in:
Vansh-Sharma27 2026-07-26 19:34:09 +05:30
parent 07cc9e1886
commit b4a93124c8
No known key found for this signature in database
2 changed files with 69 additions and 2 deletions

View File

@ -805,9 +805,23 @@ class EmbeddingClient:
``hf:`` tokenizer specs fetch from the Hugging Face Hub; doing that on
the first request would stall the event loop under the singleton lock.
Calling this from the API and deriver lifespans moves any tokenizer
download off the request path and fails the process fast on a bad spec.
download off the request path and fails the process fast on a bad
tokenizer spec. Any other construction error (e.g. a missing API key)
is logged and deferred to first use, so deployments that never embed
keep starting up exactly as they did before warmup existed.
"""
self._get_client()
try:
self._get_client()
except ValidationException:
# An explicitly configured tokenizer spec that cannot load is a
# misconfiguration of this feature; keep failing fast.
raise
except Exception:
logger.warning(
"Embedding client warmup failed; embedding calls will fail "
+ "until the embedding configuration is fixed",
exc_info=True,
)
def _get_settings_signature(self) -> tuple[object, ...]:
runtime_config = self._resolve_runtime_config()

View File

@ -1282,3 +1282,56 @@ def test_settings_signature_tracks_tokenizer(
after = wrapper._get_settings_signature() # pyright: ignore[reportPrivateUsage]
assert before != after
def test_warmup_defers_missing_api_key_instead_of_failing_startup(
monkeypatch: pytest.MonkeyPatch,
caplog: pytest.LogCaptureFixture,
) -> None:
"""A keyless embedding config must not crash startup: warmup logs and
defers the failure to first use, matching pre-warmup lazy behavior."""
from src.embedding_client import EmbeddingClient
wrapper = EmbeddingClient()
monkeypatch.setattr(EmbeddingClient, "_instance", None)
monkeypatch.setattr(EmbeddingClient, "_instance_signature", None)
monkeypatch.setattr(
wrapper,
"_resolve_runtime_config",
lambda: EmbeddingModelConfig(
transport="openai",
model="text-embedding-3-small",
api_key=None,
),
)
with caplog.at_level("WARNING", logger="src.embedding_client"):
wrapper.warmup()
assert EmbeddingClient._instance is None # pyright: ignore[reportPrivateUsage]
assert "warmup failed" in caplog.text
def test_warmup_still_fails_fast_on_bad_tokenizer_spec(
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""An explicitly configured tokenizer spec that cannot load is a
misconfiguration of the tokenizer feature and must keep failing startup."""
from src.embedding_client import EmbeddingClient
wrapper = EmbeddingClient()
monkeypatch.setattr(EmbeddingClient, "_instance", None)
monkeypatch.setattr(EmbeddingClient, "_instance_signature", None)
monkeypatch.setattr(
wrapper,
"_resolve_runtime_config",
lambda: EmbeddingModelConfig(
transport="openai",
model="text-embedding-3-small",
api_key="test-key",
tokenizer="tiktoken:",
),
)
with pytest.raises(ValidationException, match="requires an encoding name"):
wrapper.warmup()