From 86a249d01437f1cd0b4d5d51c90435c0ba89992f Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Mon, 30 Mar 2026 03:44:35 -0300 Subject: [PATCH] atlasbot: enforce per-call timeout across retries --- atlasbot/llm/client.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/atlasbot/llm/client.py b/atlasbot/llm/client.py index 3baf595..9e4253b 100644 --- a/atlasbot/llm/client.py +++ b/atlasbot/llm/client.py @@ -1,5 +1,6 @@ import json import logging +import time from typing import Any import httpx @@ -42,9 +43,16 @@ class LLMClient: "stream": False, } timeout = timeout_sec if timeout_sec is not None else self._timeout + deadline = (time.monotonic() + timeout) if timeout_sec is not None else None for attempt in range(max(1, self._settings.ollama_retries + 1)): + call_timeout = timeout + if deadline is not None: + remaining = deadline - time.monotonic() + if remaining <= 0: + raise LLMError("timeout") + call_timeout = min(call_timeout, remaining) try: - async with httpx.AsyncClient(timeout=timeout) as client: + async with httpx.AsyncClient(timeout=call_timeout) as client: resp = await client.post(self._endpoint(), json=payload, headers=self._headers) if resp.status_code == FALLBACK_STATUS_CODE and self._settings.ollama_fallback_model: payload["model"] = self._settings.ollama_fallback_model @@ -61,6 +69,8 @@ class LLMClient: return str(content) except Exception as exc: log.warning("ollama call failed", extra={"extra": {"attempt": attempt + 1, "error": str(exc)}}) + if deadline is not None and (deadline - time.monotonic()) <= 0: + raise LLMError("timeout") from exc if attempt + 1 >= max(1, self._settings.ollama_retries + 1): raise LLMError(str(exc)) from exc raise LLMError("ollama retries exhausted")