Skip to content

feat(retry): 重试间隔与传输错误粘滞同号重试#334

Merged
james-6-23 merged 1 commit into
mainfrom
feat/retry-interval-sticky-transport
Jul 8, 2026
Merged

feat(retry): 重试间隔与传输错误粘滞同号重试#334
james-6-23 merged 1 commit into
mainfrom
feat/retry-interval-sticky-transport

Conversation

@james-6-23

@james-6-23 james-6-23 commented Jul 8, 2026

Copy link
Copy Markdown
Owner

说明

实现 #331 的两个诉求。新增两个系统设置,默认值完全保持旧行为(间隔 0、策略 rotate),老部署无感。

Closes #331

retry_interval_ms — 重试间隔(0~30000ms,默认 0)

两次重试之间等待配置的间隔,等待期间客户端断开立即中止(waitBeforeRetryselect ctx.Done() 实现,sleep 前已释放账号并发槽)。

覆盖的重试点:传输错误、上游非 200 状态、首包前断流透明重试、WS 静默重试(Responses 主循环 / OpenAI 直连分支 / ChatCompletions / compact 两分支 / 入站 WS)。首字超时重试不叠加间隔——那条路径已经白等了一轮超时。

transport_retry_policy — 传输错误重试策略(rotate 默认 / sticky)

issue 里的两个场景(梯子换节点、网络断几秒)都是连接级传输错误,故障根源不在账号。sticky 模式下:

  • 不换号:不 MarkHard、不解绑会话亲和,下一轮自然拿回同一账号;
  • 不记账号失败:跳过 ReportRequestFailure,网络问题不再污染账号健康度;
  • 等间隔后重试。

范围刻意收窄到传输错误:5xx/401/429 是上游针对账号返回的,粘滞重试大概率复现同样错误,仍按旧逻辑换号。这也是没有完全按 issue 中"非 401/429 都粘滞"实现的原因,如有需要可后续加一档 scope 设置。

链路

system_settings 两列(pg ADD COLUMN IF NOT EXISTS / sqlite 列迁移)→ admin settings API(0-30000 clamp / 枚举归一)→ store atomics → proxy 读取;前端设置页在"最大重试次数"旁新增数字输入与策略下拉(中英文案)。

测试

  • waitBeforeRetry:间隔 0 快路径 / ctx 已取消 / 按间隔等待 / 等待中取消即时中止
  • 设置归一化:负值→0、超限→30000、未知策略→rotate
  • 入站 WS 端到端:首次上游连接报 connection reset、第二次成功 —— sticky 断言两次同号,rotate 断言换号
  • go build ./...go test ./...、前端 tsc --noEmit + vite build 全部通过

Summary by CodeRabbit

  • New Features

    • Added configurable retry interval and transport retry policy settings in the app.
    • Introduced a sticky retry option to keep the same upstream selection during certain transport failures.
  • Bug Fixes

    • Retries now respect a configurable wait time and stop promptly if the client disconnects.
    • Retry behavior is now consistently applied across response, chat, and WebSocket flows.
  • Tests

    • Added coverage for retry timing, setting normalization, and sticky vs. rotating retry behavior.

新增两个系统设置(默认值保持旧行为,老部署无感):

retry_interval_ms(0-30000,默认 0 = 立即重试):
- 两次重试之间等待配置的间隔,等待期间客户端断开立即中止
- 覆盖:传输错误重试、上游非 200 状态重试、首包前断流透明重试、
  WS 静默重试(Responses 主循环 / OpenAI 直连 / ChatCompletions /
  compact 两分支 / 入站 WS)
- 首字超时重试不叠加间隔(已白等一轮)

transport_retry_policy(rotate 默认 / sticky):
- 网络波动、代理换节点等连接级失败(classifyTransportFailure 命中)
  的根源不在账号:sticky 模式下不换号、不记账号失败(避免误伤健康度)、
  不解绑会话亲和、不硬排除,等间隔后同号重试
- 上游 HTTP 状态错误(5xx/401/429)与流断仍按旧逻辑换号,
  因为这些是上游针对账号返回的,粘滞意义存疑

链路:system_settings 两列(pg/sqlite 迁移)→ admin settings API →
store atomics → proxy 读取;前端设置页在最大重试次数旁新增两个控件。

测试:waitBeforeRetry 间隔/取消行为、设置归一化、
入站 WS 端到端 sticky 同号 / rotate 换号各一条。
@james-6-23 james-6-23 merged commit 9741c20 into main Jul 8, 2026
8 of 9 checks passed
@james-6-23 james-6-23 deleted the feat/retry-interval-sticky-transport branch July 8, 2026 14:50
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7313528a-c2fc-417c-a1ba-ba26a5dad0f0

📥 Commits

Reviewing files that changed from the base of the PR and between 53c6408 and 6fe0646.

📒 Files selected for processing (11)
  • admin/handler.go
  • auth/store.go
  • database/postgres.go
  • database/sqlite.go
  • frontend/src/locales/en.json
  • frontend/src/locales/zh.json
  • frontend/src/pages/Settings.tsx
  • frontend/src/types.ts
  • proxy/handler.go
  • proxy/responses_ws.go
  • proxy/retry_interval_test.go

📝 Walkthrough

Walkthrough

Adds configurable retry interval (retry_interval_ms) and transport retry policy (transport_retry_policy, rotate/sticky) settings, persisted in Postgres/SQLite and exposed via admin API and auth Store. Proxy retry loops for /v1/responses, /v1/responses/compact, /v1/chat/completions, and WebSocket paths use these to wait before retry and preserve account affinity for sticky retries. Frontend settings UI/i18n and tests are added.

Changes

Configurable retry interval and sticky transport retry

Layer / File(s) Summary
Database schema and persistence
database/postgres.go, database/sqlite.go
Adds retry_interval_ms and transport_retry_policy columns/defaults, extends SystemSettings, read/write queries, and normalization helpers (normalizeRetryIntervalMSDB, NormalizeTransportRetryPolicy).
Auth store runtime config
auth/store.go
Adds atomic fields, initialization from settings, and normalized getters/setters for retry interval and transport retry policy.
Admin settings API
admin/handler.go
Extends GetSettings/UpdateSettings request/response models to read, validate/clamp, apply, and persist the new fields.
Proxy retry loops
proxy/handler.go, proxy/responses_ws.go
Adds waitBeforeRetry/stickyTransportRetryEnabled helpers and wires sticky retry (skip failure reporting/session unbinding) plus wait-before-retry into HTTP and WebSocket retry paths.
Frontend settings UI and i18n
frontend/src/types.ts, frontend/src/pages/Settings.tsx, frontend/src/locales/en.json, frontend/src/locales/zh.json
Adds new type fields, form controls/defaults, and localized labels for retry interval and transport retry policy.
Tests
proxy/retry_interval_test.go
Adds tests for wait behavior, settings normalization, and sticky vs rotate WebSocket retry account selection.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Handler
  participant Store
  participant Upstream

  Client->>Handler: request (/v1/responses)
  Handler->>Upstream: forward request
  Upstream-->>Handler: transport error
  Handler->>Handler: compute stickyRetry
  alt stickyRetry
    Handler->>Handler: skip ReportRequestFailure, keep session affinity
  else not sticky
    Handler->>Handler: ReportRequestFailure, UnbindSessionAffinity
  end
  Handler->>Store: GetRetryIntervalMS
  Handler->>Handler: waitBeforeRetry
  alt client context canceled
    Handler-->>Client: return early
  else
    Handler->>Upstream: retry request
    Upstream-->>Handler: success
    Handler-->>Client: response
  end
Loading

Possibly related PRs

  • james-6-23/codex2api#246: Both PRs modify proxy/handler.go's /v1/responses and /v1/responses/compact retry/error-handling paths.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/retry-interval-sticky-transport

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Idea] 重试功能不够完善

1 participant