Skip to content

增加渠道重试优先级模式 - #2729

Closed
zhang2023san-oss wants to merge 2 commits into
QuantumNous:mainfrom
zhang2023san-oss:feature/retry-priority-modes
Closed

增加渠道重试优先级模式#2729
zhang2023san-oss wants to merge 2 commits into
QuantumNous:mainfrom
zhang2023san-oss:feature/retry-priority-modes

Conversation

@zhang2023san-oss

@zhang2023san-oss zhang2023san-oss commented Jan 23, 2026

Copy link
Copy Markdown

功能描述

本 PR 包含两个相关的渠道重试增强功能:

  1. 重试时避开已尝试渠道(Commit: 4de4c07

在渠道重试过程中,系统会自动排除已经尝试过的渠道,避免重复请求同一个失败的渠道。

功能特性:

  • 新增配置选项 RetryAvoidUsedChannelEnabled,可在运营设置中开启/关闭
  • 重试时自动记录已使用的渠道 ID
  • 在选择下一个渠道时排除已使用的渠道
  • 前端新增开关按钮,支持动态配置
  1. 渠道重试优先级模式(Commit: 3d0c7f9

实现了两种渠道重试的优先级模式,用户可根据业务需求选择:

Sequential(顺序模式):

  • 同一优先级内尝试所有渠道后才降级到下一优先级
  • 例如:A1 → A2 → A3 → B1 → B2 → B3
  • 适合希望充分利用高优先级渠道的场景

Round-robin(轮询模式):

  • 每个优先级轮流尝试,实现负载均衡
  • 例如:A1 → B1 → C1 → A2 → B2 → C2
  • 适合希望分散请求压力的场景

实现细节

功能 1: 重试避开已尝试渠道

修改的文件:

  1. common/constants.go
    - 新增 RetryAvoidUsedChannelEnabled 配置常量
  2. model/option.go
    - 添加配置项的加载和更新逻辑
  3. controller/relay.go
    - 在重试循环中记录已使用的渠道 ID
    - 将排除列表传递给渠道选择函数
  4. service/channel_select.go
    - 新增 UsedChannelIds 字段到 RetryParam 结构体
    - 将排除列表传递给底层查询函数
  5. model/ability.go & model/channel_cache.go
    - 在渠道查询时应用排除逻辑
    - 使用 NOT IN 子句过滤已使用的渠道
  6. 前端文件
    - web/src/pages/Setting/Operation/SettingsMonitoring.jsx - 新增开关按钮
    - web/src/i18n/locales/zh.json & en.json - 国际化文本

功能 2: 渠道重试优先级模式

修改的文件:

  1. model/option.go (line 414-417)
    - 修复了 RetryPriorityMode 配置加载问题
    - 原本错误地放在了只处理 "Enabled" 结尾配置项的条件块内
  2. model/ability.go (line 82-92)
    - 在 getPriority 函数中添加了 round-robin 模式的模运算逻辑
    - 确保在轮询模式下正确循环优先级
  3. model/channel_cache.go (line 149-155)
    - 在 GetRandomSatisfiedChannel 函数中添加了 round-robin 模式的模运算逻辑
    - 支持内存缓存场景下的轮询模式
  4. controller/relay.go (line 229-237)
    - 移除了 round-robin 模式下的 IncreasePriorityIndex() 调用
    - 避免双重优先级切换导致的跳过问题
  5. service/channel_select.go (line 184-201)
    - 区分两种模式的参数传递
    - Round-robin 模式传递 retry 参数
    - Sequential 模式传递 priorityIndex 参数
  6. 前端文件
    - web/src/pages/Setting/Operation/SettingsMonitoring.jsx - 优先级模式选择器
    - web/src/i18n/locales/zh.json & en.json - 国际化文本

核心逻辑

Round-robin 模式:
if common.RetryPriorityMode == "round-robin" && len(priorities) > 0 {
priorityToUse = priorities[retry%len(priorities)]
}

Sequential 模式:
if retry >= len(priorities) {
priorityToUse = priorities[len(priorities)-1]
} else {
priorityToUse = priorities[retry]
}

渠道排除逻辑:
if len(excludeIds) > 0 {
var excludeIdList []int
for id := range excludeIds {
excludeIdList = append(excludeIdList, id)
}
channelQuery = channelQuery.Where("channel_id NOT IN ?", excludeIdList)
}

测试结果

功能 1: 重试避开已尝试渠道

  • ✅ 开启功能后,重试时不会选择已失败的渠道
  • ✅ 日志正确显示排除的渠道数量
  • ✅ 前端开关可正常切换配置

功能 2: 渠道重试优先级模式

测试环境:

  • 4 个渠道:2, 3 (优先级 10),5, 6 (优先级 0)
  • 2 个唯一优先级:[10, 0]

Round-robin 模式测试结果:
retry=0 → 渠道 #2 (优先级 10) ✓
retry=1 → 渠道 #5 (优先级 0) ✓
retry=2 → 渠道 #3 (优先级 10) ✓
retry=3 → 渠道 #6 (优先级 0) ✓

符合预期的轮询模式:在优先级之间交替选择。

相关 Issue

(如果有相关 issue,请在此处引用)

检查清单

  • 代码已通过编译
  • 已在本地测试 round-robin 模式
  • 已在本地测试渠道排除功能
  • 已移除调试日志
  • 需要测试 sequential 模式(建议维护者测试)
  • 代码符合项目规范
  • 已更新相关文档(前端国际化文件)

备注

  1. 功能 1 提供了基础的渠道排除能力,避免重复请求失败的渠道
  2. 功能 2 修复了 round-robin 模式的核心逻辑问题,确保在重试时能够正确地在不同优先级之间轮换
  3. 两个功能可以独立使用,也可以组合使用以获得最佳的重试效果

Summary by CodeRabbit

  • New Features

    • Added "Avoid used channels on retry" option to skip previously failed channels during retries
    • Added "Retry Priority Mode" selection with sequential and round-robin options for retry behavior control
  • Documentation

    • Added configuration UI controls and multi-language localization support (English and Chinese)

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 23, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR implements an enhanced channel retry mechanism with two new configuration options: the ability to exclude already-failed channels from retry attempts, and support for both sequential and round-robin priority selection modes during retries. The feature spans backend logic, data models, service layer, and frontend UI components.

Changes

Cohort / File(s) Summary
Core Configuration
common/constants.go
Adds two global variables: RetryAvoidUsedChannelEnabled (bool, default false) and RetryPriorityMode (string, default "sequential"); controls feature activation.
Data Model & Channel Selection
model/ability.go, model/channel_cache.go
Extended GetChannel and GetRandomSatisfiedChannel signatures to accept excludeIds parameter for filtering. Implements round-robin priority cycling using retry modulo and sequential fallback logic.
Retry Coordination & Tracking
service/channel_select.go, controller/relay.go
Added UsedChannelIds and CurrentPriorityIndex fields to RetryParam struct with accessor methods. Tracks used channels during retries, propagates exclusions through selection flow, handles nil channel returns to signal priority advancement.
Configuration Management
model/option.go
Adds option handlers for RetryAvoidUsedChannelEnabled and RetryPriorityMode with validation that mode accepts only "sequential" or "round-robin".
Frontend Settings & Localization
web/src/components/settings/OperationSetting.jsx, web/src/pages/Setting/Operation/SettingsMonitoring.jsx
Adds UI state and controls (Switch, Select dropdown) for new settings.
Localization
web/src/i18n/locales/en.json, web/src/i18n/locales/zh.json
Adds translation keys for UI labels in both English and Chinese covering feature toggle, mode selection, and descriptions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • creamlike1024
  • xyfacai

Poem

🐰 A clever warren redesigns its paths,
Avoiding channels worn from failed attempts,
Sequential or round-robin hops so spry,
Each retry smarter than the last—
No rabbit circles back to empty warrens! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: adding channel retry priority modes (sequential and round-robin), which is the core feature. The title is clear, concise, and specific.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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 and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
service/channel_select.go (1)

147-201: Auto-group retries may skip lower priorities when exclusions are enabled.

model.GetRandomSatisfiedChannel now returns nil when only the current priority is exhausted due to exclusions. In the auto-group branch, nil is treated as “group has no channel” and immediately advances to the next group, which can skip lower priorities within the same group and violates the “exhaust all priorities before switching” behavior described above.

Consider distinguishing “priority exhausted” vs “group empty” (e.g., a sentinel error/flag from GetRandomSatisfiedChannel) and only advance groups when the group is truly exhausted; otherwise advance priority within the same group.

🤖 Fix all issues with AI agents
In `@model/option.go`:
- Around line 414-417: The branch handling the "RetryPriorityMode" option
currently accepts any value into common.OptionMap and only sets
common.RetryPriorityMode for "sequential" or "round-robin", causing invalid
values to persist; modify the setter in the switch for "RetryPriorityMode" to
validate the incoming value and return an error for any unsupported value
instead of silently accepting it, and update UpdateOption to validate
RetryPriorityMode (and any similar enums) before persisting to the DB — if a
validation fails, restore the previous entry in common.OptionMap (or avoid
mutating it) and return the error so the UI does not show “saved.” Ensure
references to RetryPriorityMode, common.RetryPriorityMode, common.OptionMap and
the UpdateOption function are used to locate and change the logic.

Comment thread model/option.go
Comment on lines +414 to +417
case "RetryPriorityMode":
if value == "sequential" || value == "round-robin" {
common.RetryPriorityMode = value
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Reject invalid RetryPriorityMode values instead of silently accepting them

Right now an unsupported value still gets stored in common.OptionMap and the update returns nil, so the UI sees “saved” even though runtime keeps the old mode. Since UpdateOption saves to DB before validation, this can persist a bad value and create a confusing mismatch.

Consider validating and returning an error (and restoring the OptionMap entry). Ideally validate before DB save in UpdateOption as well.

🛠️ Suggested fix
-import (
-	"strconv"
-	"strings"
-	"time"
+import (
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
@@
 	case "RetryPriorityMode":
-		if value == "sequential" || value == "round-robin" {
-			common.RetryPriorityMode = value
-		}
+		if value != "sequential" && value != "round-robin" {
+			common.OptionMap[key] = common.RetryPriorityMode
+			return fmt.Errorf("invalid RetryPriorityMode: %s", value)
+		}
+		common.RetryPriorityMode = value
🤖 Prompt for AI Agents
In `@model/option.go` around lines 414 - 417, The branch handling the
"RetryPriorityMode" option currently accepts any value into common.OptionMap and
only sets common.RetryPriorityMode for "sequential" or "round-robin", causing
invalid values to persist; modify the setter in the switch for
"RetryPriorityMode" to validate the incoming value and return an error for any
unsupported value instead of silently accepting it, and update UpdateOption to
validate RetryPriorityMode (and any similar enums) before persisting to the DB —
if a validation fails, restore the previous entry in common.OptionMap (or avoid
mutating it) and return the error so the UI does not show “saved.” Ensure
references to RetryPriorityMode, common.RetryPriorityMode, common.OptionMap and
the UpdateOption function are used to locate and change the logic.

@seefs001 seefs001 closed this Jan 25, 2026
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.

2 participants