From 0e70fa47f9ed8ba5ec4bc6128e73c67d66b6d597 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 20 May 2026 17:10:40 +0400 Subject: [PATCH] v2.5.1: adaptive retry for 429/502/503, socket reuse, BGP retry - Exponential backoff retry (2s/4s/8s) for rate limits and transient errors - BGP routes retry before failing over to next route - Socket SO_REUSEADDR prevents 'Address already in use' crashes - Connection reset/broken pipe also retried - BGP route count shown at proxy startup --- CHANGELOG.md | 10 +++++ codex-launcher_2.5.0_all.deb | Bin 31568 -> 0 bytes codex-launcher_2.5.1_all.deb | Bin 0 -> 32020 bytes src/codex-launcher-gui | 8 +++- src/translate-proxy.py | 81 ++++++++++++++++++++++++++--------- 5 files changed, 77 insertions(+), 22 deletions(-) delete mode 100644 codex-launcher_2.5.0_all.deb create mode 100644 codex-launcher_2.5.1_all.deb diff --git a/CHANGELOG.md b/CHANGELOG.md index 26736a9..8efdc3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## v2.5.1 (2026-05-20) + +- **Adaptive retry for transient errors** (429/502/503) + - Exponential backoff: 2s → 4s → 8s, up to 3 retries + - Works for both single-provider and BGP mode + - BGP routes retry before failing over to next route + - Connection errors (reset/broken pipe) also retried +- **Proxy socket reuse** — no more `Address already in use` crashes on restart +- **BGP startup log** shows route count and names + ## v2.5.0 (2026-05-20) - **AI BGP — Multi-provider routing with automatic failover** diff --git a/codex-launcher_2.5.0_all.deb b/codex-launcher_2.5.0_all.deb deleted file mode 100644 index bd99b79f1c7267df16d36f624cece633f8c8bbb8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31568 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 X7v1u{G4VYn`^2wSTe diff --git a/codex-launcher_2.5.1_all.deb b/codex-launcher_2.5.1_all.deb new file mode 100644 index 0000000000000000000000000000000000000000..22ad5acf4c8aea9d8294e169569976e33452e406 GIT binary patch literal 32020 zcmaf)Q;aZ55Ukg>ZQHhO+qP}nw*9Yd+qP|c@40-voyjEg(8;`flj^DrA&;Sxu>~KL ziK&sLp&hM}rJbRZCjkKgBRe}M69*F;BNG7u!++=hyE8H{u(7ZZ5d63PPZ>Zl(J??7 z+uOM~+1t>$7&_5;IlKIS``I~}|6e~v3;mA?0J$y(0GV|Nqk*k61I!QuOtSDbyc0r_ zB$Lvy2=Z%rYJ_OO&LOKwANPQTOj~$FLyy&pGydBK84 z%7Oh>1^slpA$;K3mPHulF8@&%2W9?V_>W?+o}&s%BvqLVR&878)9QY=ybw;T;&{re z9+*!?ByMygg_ToHRS}J}kthW)aAe7EvJj=0)Q;in+bb8M8`<)3CWZ{Mq^YcGh!Yt( zQl?BC3h2X0&+_@am$70n*NA{R=;kyOh#&%*WE6|~SB50g$f|!WSG!bZRH{`!DMr8Pe_O@pmwn}1g5#ZzeIx@7guG=M!vUh~t( zlkwJis)OD&(XI^x+g>-O8w^c9dPwL;)pQ-wHA--Y5Fp}&Nl}f}(<_x|+||__9v;m} zZj#W8K}ri><&UMBlQ-!t_zQoH-Wr0xwxw7s2m*sKSa-s3tH8R z{K{y|4i$>hvLL_>Z!y1}2lV(psC#Q}<)43p?WFSeyNUIrL>eCxM+|1C4uFlu=`8 zcM9w^c8>;r~PGKVJTSR5CL% zF#m5d4WRxfRUj51Z$OEPdMky{I4f#=Q-K01X~?DgnsaRU_(L_QL0#U)G|~{fwaUIez7}={d?aanzkW zZpz(UZco}?)0*$PuN8hYJkj^At>R^CsGpJv)_8_`R}sX*}vV4TzEB<{oze#em&WZn=zZ*Ok1(rM|ipV zKKVp*y8C!d-kCCA*|z*?Jgj%+0NjWURJC>rvNoT-NTG(-7%+eae3AFaF2_>Qw2b?kk<) zAN>eBL<-TXAdYco|E>|)my(rLu@~R1<^T1X7qS#p{#5;}KDBLR=5z818cuNdDwN)J znSE~@=&JZvTP_b}s?9y|+WW0LHdtGirpjNZM^Pir;q7Y~*YVRrY~Tg%sc7nWiFzelLYZ)>=6l@Q&T``Gif zz}&&h31D9UHIj$qqvP6dNv@!rqnZXR3~a0x2TbC{!Q_Xtf}1-B+hNZ6>K|YvJ3&Lu zr6TKneH9oOw323$IB;so0imTu1(t&XpglE6i1tea!x=d5aiaz!1$#2LW$Uq{uFaJt zzyDTtrZZxfej55&o5REx7lyos2qz;Up`eluRVD-^45?*ovt8b(If8)e;2c{S6>-RZ(W%0D;XIb6`2Zw0;MDbD;f%Tu|L1+5b=~B5L_8* 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 F(fWwL32FcU literal 0 HcmV?d00001 diff --git a/src/codex-launcher-gui b/src/codex-launcher-gui index 8cf1803..9fd8e7c 100755 --- a/src/codex-launcher-gui +++ b/src/codex-launcher-gui @@ -25,6 +25,12 @@ model_catalog_json = "" """ CHANGELOG = [ + ("2.5.1", "2026-05-20", [ + "Adaptive retry for 429/502/503 errors with exponential backoff", + "BGP routes also retry transient errors before failing over", + "Proxy socket reuse — no more 'Address already in use' crashes", + "BGP route count shown at proxy startup", + ]), ("2.5.0", "2026-05-20", [ "AI BGP — multi-provider routing with automatic failover", "Create BGP pools with ordered routes from any configured endpoint", @@ -629,7 +635,7 @@ class LauncherWin(Gtk.Window): # header row hdr = Gtk.Box(spacing=8) vbox.pack_start(hdr, False, False, 0) - lbl = Gtk.Label(label="Codex Launcher v2.5.0") + lbl = Gtk.Label(label="Codex Launcher v2.5.1") lbl.set_use_markup(True) hdr.pack_start(lbl, False, False, 0) changelog_btn = Gtk.Button(label="Changelog") diff --git a/src/translate-proxy.py b/src/translate-proxy.py index 6d3997b..80e4e69 100755 --- a/src/translate-proxy.py +++ b/src/translate-proxy.py @@ -1041,14 +1041,30 @@ class Handler(http.server.BaseHTTPRequestHandler): "Authorization": f"Bearer {effective_key}", }, browser_ua=True) print(f"[translate-proxy] POST {target} model={model} stream={stream} items={len(input_data) if isinstance(input_data,list) else 1}", file=sys.stderr) - req = urllib.request.Request(target, data=json.dumps(chat_body).encode(), headers=fwd) - try: - upstream = urllib.request.urlopen(req, timeout=180) - except urllib.error.HTTPError as e: - err = e.read().decode() - return self.send_json(e.code, {"error": {"type": "upstream_error", "message": err}}) - except Exception as e: - return self.send_json(500, {"error": {"type": "proxy_error", "message": str(e)}}) + chat_body_b = json.dumps(chat_body).encode() + max_retries = 3 + for attempt in range(max_retries + 1): + req = urllib.request.Request(target, data=chat_body_b, headers=fwd) + try: + upstream = urllib.request.urlopen(req, timeout=180) + except urllib.error.HTTPError as e: + err_body = e.read().decode() + if e.code in (429, 502, 503) and attempt < max_retries: + wait = min(2 ** (attempt + 1), 15) + print(f"[translate-proxy] HTTP {e.code} (attempt {attempt+1}/{max_retries}), retrying in {wait}s: {err_body[:150]}", file=sys.stderr) + time.sleep(wait) + continue + return self.send_json(e.code, {"error": {"type": "upstream_error", "message": err_body}}) + except (ConnectionResetError, ConnectionAbortedError, BrokenPipeError) as e: + if attempt < max_retries: + wait = min(2 ** (attempt + 1), 10) + print(f"[translate-proxy] connection error (attempt {attempt+1}/{max_retries}), retrying in {wait}s: {e}", file=sys.stderr) + time.sleep(wait) + continue + return self.send_json(502, {"error": {"type": "proxy_error", "message": str(e)}}) + except Exception as e: + return self.send_json(500, {"error": {"type": "proxy_error", "message": str(e)}}) + break self._forward_oa_compat(upstream, stream, model, chat_body, body, input_data, fwd, target) def _build_chat_body(self, model, messages, body, stream): @@ -1108,18 +1124,37 @@ class Handler(http.server.BaseHTTPRequestHandler): }, browser_ua=True) print(f"[bgp] trying route '{route.get('name', r_url)}' model={r_model}", file=sys.stderr) req = urllib.request.Request(target, data=json.dumps(chat_body).encode(), headers=fwd) - try: - upstream = urllib.request.urlopen(req, timeout=180) - print(f"[bgp] route '{route.get('name', r_url)}' connected OK", file=sys.stderr) - self._forward_oa_compat(upstream, stream, r_model, chat_body, body, input_data, fwd, target) - return - except urllib.error.HTTPError as e: - err = e.read().decode() - print(f"[bgp] route '{route.get('name', r_url)}' FAILED: HTTP {e.code}: {err[:200]}", file=sys.stderr) - errors.append(f"{route.get('name','?')}: HTTP {e.code}") - except Exception as e: - print(f"[bgp] route '{route.get('name', r_url)}' FAILED: {e}", file=sys.stderr) - errors.append(f"{route.get('name','?')}: {e}") + route_ok = False + for attempt in range(3): + try: + upstream = urllib.request.urlopen(req, timeout=180) + print(f"[bgp] route '{route.get('name', r_url)}' connected OK", file=sys.stderr) + self._forward_oa_compat(upstream, stream, r_model, chat_body, body, input_data, fwd, target) + return + except urllib.error.HTTPError as e: + err = e.read().decode() + if e.code in (429, 502, 503) and attempt < 2: + wait = min(2 ** (attempt + 1), 10) + print(f"[bgp] route '{route.get('name', r_url)}' HTTP {e.code}, retry {attempt+1}/2 in {wait}s", file=sys.stderr) + time.sleep(wait) + req = urllib.request.Request(target, data=json.dumps(chat_body).encode(), headers=fwd) + continue + print(f"[bgp] route '{route.get('name', r_url)}' FAILED: HTTP {e.code}: {err[:200]}", file=sys.stderr) + errors.append(f"{route.get('name','?')}: HTTP {e.code}") + break + except (ConnectionResetError, ConnectionAbortedError, BrokenPipeError) as e: + if attempt < 2: + wait = min(2 ** (attempt + 1), 8) + print(f"[bgp] route '{route.get('name', r_url)}' conn error, retry {attempt+1}/2 in {wait}s: {e}", file=sys.stderr) + time.sleep(wait) + req = urllib.request.Request(target, data=json.dumps(chat_body).encode(), headers=fwd) + continue + errors.append(f"{route.get('name','?')}: {e}") + break + except Exception as e: + print(f"[bgp] route '{route.get('name', r_url)}' FAILED: {e}", file=sys.stderr) + errors.append(f"{route.get('name','?')}: {e}") + break print(f"[bgp] ALL ROUTES FAILED: {errors}", file=sys.stderr) self.send_json(502, {"error": {"type": "bgp_all_routes_failed", "message": f"All BGP routes failed: {'; '.join(errors)}"}}) @@ -1440,8 +1475,12 @@ class Handler(http.server.BaseHTTPRequestHandler): print(f"[translate-proxy] {BACKEND} {msg}", file=sys.stderr) if __name__ == "__main__": - server = http.server.HTTPServer(("127.0.0.1", PORT), Handler) + class ReusableHTTPServer(http.server.HTTPServer): + allow_reuse_address = True + server = ReusableHTTPServer(("127.0.0.1", PORT), Handler) print(f"translate-proxy ({BACKEND}) listening on http://127.0.0.1:{PORT}", flush=True) print(f"Target: {TARGET_URL}", flush=True) print(f"Models: {[m['id'] for m in MODELS]}", flush=True) + if BGP_ROUTES: + print(f"BGP routes: {len(BGP_ROUTES)} ({[r.get('name','?') for r in BGP_ROUTES]})", flush=True) server.serve_forever()