Skip to content

rate-limit-proxy: upstream TimeoutError 完全不會走到 handle_error,逾時無法歸因 #37

Description

@kiki830621

Problem

/idd-verify #36 round 3(codex lens)發現一個獨立於 #36 本身修正邏輯的既有缺口:upstream 端的 socket.timeout/TimeoutError 完全不會走到 ThreadingHTTPServer.handle_error(),因此不管 handle_error 怎麼寫都碰不到它——這是標準庫 http.server.BaseHTTPRequestHandler.handle_one_request() 的既有行為,跟 #36 引入的 client/upstream 分類機制無關。

Original text(codex finding,逐字)
「Codex 認為這是本次設計最大的覆蓋缺口(與「標記機制對不對」無關,是標記機制構不到的區域)。四個 upstream I/O 點(_handlee.read() / upstream_resp.read() / urlopen outer except,以及 _forward_streamingupstream_resp.read(1))都只捕捉 (ConnectionResetError, BrokenPipeError)。失敗情境:1. upstream 已回 headers,urlopen() 成功回傳 HTTPResponse;2. upstream 在 body 中途停住,超過 socket timeout;3. read() / read(1)socket.timeout / TimeoutError;4. 現有 except 不捕捉它 → 例外往上傳;5. stdlib BaseHTTPRequestHandler.handle_one_request() 會捕捉 TimeoutError,印一行 Request timed out: ... 後關連線 return;6. socketserver.process_request_thread() 因此看不到例外,ThreadingHTTPServer.handle_error() 完全不會被呼叫 → 一個真正的 upstream 故障沒有任何 traceback、也沒有任何歸因訊息。」

Type

bug(observability gap,非 #36 的 client/upstream 分類邏輯本身)

Expected

upstream 逾時(socket timeout)發生時,proxy.log 應該留下可歸因的訊息(至少要能分辨「這是 upstream 逾時,不是別的」),而不是完全沉默。

Actual

BaseHTTPRequestHandler.handle_one_request() 在 stdlib 層級就把 TimeoutError 攔截並印一行泛用的 Request timed out: ...(不經過 handle_error(),也不含任何 upstream-specific 的歸因資訊),然後直接關閉連線 return。任何在 handle_error() 裡加的邏輯(含 #36 新增的 client/upstream 分類)對這個路徑完全不可見。

Impact

  • upstream 逾時(例如 api.anthropic.com 回應緩慢或掛起)目前只留下一行通用訊息,無法從 log 判斷是哪個 request、什麼情境下逾時
  • 若未來要做逾時相關的可觀測性或告警,現有機制在這個路徑上完全構不到

Suggested direction(codex 建議,供 diagnose 階段判斷)

在每個 upstream I/O 邊界(urlopenupstream_resp.read()e.read()upstream_resp.read(1))額外捕捉 TimeoutError,改拋一個不繼承 TimeoutError 的自訂例外(例如 UpstreamTimeoutError(...) from exc),這樣才不會被 handle_one_request() 攔截、能正常傳到 handle_error()。更集中的做法是把四個呼叫點收斂成一個 _upstream_call() wrapper,而非逐點列舉。

Context

源頭:PsychQuant/claude-hot-limit#36 的 verify round 3(pai-ensemble,codex lens,2026-08-26)。#36 本身的 client/upstream 斷線分類已修正並驗證(3 輪 verify),本 issue 是驗證過程中發現的獨立既有缺口,不阻擋 #36 close。

相關檔案:plugins/claude-hot-limit/proxy/rate-limit-proxy.py_handle() / _forward_streaming() / ThreadingHTTPServer.handle_error()

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions