test(providers): Mistral batch retry + retry-log detail + comment (#893 r4)

Round-4 review on PR #893 (no blockers, minor items):
- Document why Mistral's _is_transient is SDK-level only (429/5xx): a bare
  connection drop the SDK surfaces as httpx/ConnectionError isn't an SDKError
  and isn't retried here by design — the pod-rollover target is the gateway
  (OpenAI-compatible) path, which does cover connection errors.
- Include the last error (%r) in the retry helper's "not resolved after N
  attempts" error log.
- Add test_mistral_embed_batch_retries_on_5xx (batch path parity with embed()).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-11 06:45:56 +02:00
co-authored by Claude Opus 4.8
parent c4b6d4a017
commit 81f7403b12
3 changed files with 31 additions and 2 deletions
+2 -1
View File
@@ -77,10 +77,11 @@ def retry_on_transient(
retry_delay = min(retry_delay * 2, MAX_RETRY_DELAY)
logger.error(
"%s %s not resolved after %d attempts",
"%s %s not resolved after %d attempts: %r",
provider_name,
label,
MAX_RETRIES,
last_error,
)
if last_error is None: # pragma: no cover — loop above always sets this
raise RuntimeError("retry loop exited without capturing an error")
+9 -1
View File
@@ -31,7 +31,15 @@ _NO_EMBEDDING_MODEL_MSG = "Embedding not supported - no embedding_model configur
def _is_transient(exc: BaseException) -> bool:
"""Retry HTTP 429 (rate limit) and 5xx (server/transient) SDKErrors."""
"""Retry HTTP 429 (rate limit) and 5xx (server/transient) SDKErrors.
Scope is deliberately SDK-level: only ``SDKError`` (an HTTP-status error) is
caught by the decorator, so a pure connection drop that the Mistral SDK
surfaces as a bare ``httpx``/``ConnectionError`` is NOT retried here. The
primary pod-rollover resilience target (card 309) is the gateway path via
the OpenAI-compatible client, which does cover connection errors; direct
Mistral is a self-hoster fallback where 429/5xx is the common transient.
"""
status = getattr(exc, "status_code", None)
return status == 429 or (isinstance(status, int) and status >= 500)