diff --git a/app/ai/client.py b/app/ai/client.py index 3c77163..bebe291 100644 --- a/app/ai/client.py +++ b/app/ai/client.py @@ -139,12 +139,14 @@ def is_deferrable_error(exc: Exception) -> bool: 보류 = 맥북 일시 불가 신호: - HTTP 503 (라우터 upstream_cold / editor_busy / warming — no-silent-fallback 계약) + - HTTP 502/504 (라우터가 upstream 연결 실패·생성 도중 절단을 502 로 변환 — + llm_router.py 실측 4곳. 맥북 sleep 절단이 라우터 경유 토폴로지에선 이걸로 표면화) - httpx.TransportError 전계열 (ConnectError·ReadError·RemoteProtocolError + - ConnectTimeout·ReadTimeout 등) — 연결 실패와 생성 도중 sleep 절단을 모두 포함. + ConnectTimeout·ReadTimeout 등) — 라우터 자체 불가 / DS↔라우터 구간 절단. 그 외(400/500, 파싱/검증 오류 등)는 보류가 아니라 호출자의 기존 실패 경로. """ if isinstance(exc, httpx.HTTPStatusError): - return exc.response.status_code == 503 + return exc.response.status_code in (502, 503, 504) return isinstance(exc, httpx.TransportError) diff --git a/tests/test_macbook_offload_deep_slot.py b/tests/test_macbook_offload_deep_slot.py index e525a3d..dd237f7 100644 --- a/tests/test_macbook_offload_deep_slot.py +++ b/tests/test_macbook_offload_deep_slot.py @@ -36,9 +36,11 @@ def _http_status_error(status: int) -> httpx.HTTPStatusError: @pytest.mark.parametrize("exc", [ _http_status_error(503), # 라우터 upstream_cold/editor_busy/warming - httpx.ConnectError("connection refused"), # 맥북 sleep — 연결 자체 불가 + _http_status_error(502), # 라우터: upstream 연결 실패/생성 중 절단 변환 + _http_status_error(504), + httpx.ConnectError("connection refused"), # 라우터 자체 불가 httpx.ConnectTimeout("connect timeout"), - httpx.ReadTimeout("read timeout"), # 생성 도중 sleep 절단 + httpx.ReadTimeout("read timeout"), # DS↔라우터 구간 절단 httpx.ReadError("connection reset"), httpx.RemoteProtocolError("server disconnected"), ])