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:
parent
07cc9e1886
commit
b4a93124c8
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue