Retry Ollama 500 errors in optimistic stream with backoff
With optimistic streaming, intent (qwen2.5:1.5b) and the main stream (qwen3:latest) start concurrently. When both models are cold-loading, Ollama returns 500 for both simultaneously. The intent 500 was already handled silently in classify_intent; the stream 500 now retries up to 2 times (3s then 6s delay) before propagating as an error. 500s only occur on the first cold-load pair — subsequent requests hit warm models. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,8 @@ import re
|
|||||||
import time
|
import time
|
||||||
from collections.abc import AsyncGenerator
|
from collections.abc import AsyncGenerator
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
from sqlalchemy import update
|
from sqlalchemy import update
|
||||||
|
|
||||||
from fabledassistant.config import Config
|
from fabledassistant.config import Config
|
||||||
@@ -291,13 +293,30 @@ async def run_generation(
|
|||||||
stream_queue: asyncio.Queue[ChatChunk | BaseException | None] = asyncio.Queue(maxsize=256)
|
stream_queue: asyncio.Queue[ChatChunk | BaseException | None] = asyncio.Queue(maxsize=256)
|
||||||
|
|
||||||
async def _fill_queue() -> None:
|
async def _fill_queue() -> None:
|
||||||
try:
|
# Retry on Ollama 500 (model cold-loading race) up to 2 times.
|
||||||
async for c in stream_chat_with_tools(messages, model, tools=tools, think=think):
|
last_exc: BaseException | None = None
|
||||||
await stream_queue.put(c)
|
for attempt in range(3):
|
||||||
except BaseException as exc:
|
if attempt > 0:
|
||||||
await stream_queue.put(exc)
|
wait = 3.0 * attempt
|
||||||
finally:
|
logger.warning(
|
||||||
await stream_queue.put(None)
|
"Ollama stream 500 (attempt %d/3), retrying in %.0fs", attempt, wait
|
||||||
|
)
|
||||||
|
await asyncio.sleep(wait)
|
||||||
|
try:
|
||||||
|
async for c in stream_chat_with_tools(messages, model, tools=tools, think=think):
|
||||||
|
await stream_queue.put(c)
|
||||||
|
last_exc = None
|
||||||
|
break
|
||||||
|
except httpx.HTTPStatusError as exc:
|
||||||
|
last_exc = exc
|
||||||
|
if exc.response.status_code != 500:
|
||||||
|
break # non-500 errors are not retryable
|
||||||
|
except BaseException as exc:
|
||||||
|
last_exc = exc
|
||||||
|
break
|
||||||
|
if last_exc is not None:
|
||||||
|
await stream_queue.put(last_exc)
|
||||||
|
await stream_queue.put(None)
|
||||||
|
|
||||||
stream_fill_task = asyncio.create_task(_fill_queue())
|
stream_fill_task = asyncio.create_task(_fill_queue())
|
||||||
buf.append_event("status", {"status": "Generating response..."})
|
buf.append_event("status", {"status": "Generating response..."})
|
||||||
|
|||||||
Reference in New Issue
Block a user