Skip to content

fix(channel): unify weighted selection across cache modes - #6554

Open
faithleysath wants to merge 1 commit into
QuantumNous:mainfrom
NexusAgentX:fix/6510-channel-weight-selection
Open

fix(channel): unify weighted selection across cache modes#6554
faithleysath wants to merge 1 commit into
QuantumNous:mainfrom
NexusAgentX:fix/6510-channel-weight-selection

Conversation

@faithleysath

@faithleysath faithleysath commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

Note

AI 辅助说明:本 PR 的代码与说明由 AI 编程助手协助生成,并由提交者授权提交,请按常规标准审阅。

📝 变更描述 / Description

数据库选路当前使用 weight + 10 和闭区间边界,而内存缓存选路使用原始 weight 和半开区间,导致相同渠道配置因缓存开关不同而产生不同流量比例。

本 PR 将两条路径收敛到同一个加权选择 helper:

  • 候选总权重大于 0 时,直接按原始权重构造 [0, totalWeight) 区间。
  • 所有权重为 0 时,每个候选获得一个等长区间。
  • 部分权重为 0 时,零权重候选不获得选择区间。
  • 使用同一半开区间判断,消除数据库路径原有的首项多一个随机值、末项少一个随机值的问题。

该变更只调整渠道选择算法,不修改现有渠道配置、优先级、分组或缓存设置。

Warning

升级提示:如果某个同优先级渠道池同时包含正权重与零权重渠道,修复后零权重渠道将不再接收新流量。过去依赖零权重渠道仍获得少量流量的部署,应在升级前显式调整对应权重。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

以下检查均在最新 main@66ee6b8f 的 PR 分支上通过:

go test ./model
go test -race ./model
go test ./...
cd web && DISABLE_ESLINT_PLUGIN=true VITE_REACT_APP_VERSION=$(cat ../VERSION) bun run build

确定性测试直接验证选择区间:

weights [2, 1]    -> draws 0,1 select index 0; draw 2 selects index 1
weights [0, 0, 0] -> draws 0,1,2 分别选择三个候选
weights [0, 1, 0] -> 唯一 draw 0 只选择正权重候选

另有集成测试分别关闭和开启 MemoryCacheEnabled,确认 1:0 候选集在数据库与内存缓存路径下都只选择权重为 1 的渠道。

Use raw channel weights in both database and memory-cache routing, fall back to equal intervals only when every candidate weight is zero, and share one half-open weighted selector to avoid boundary drift.

Refs QuantumNous#6510
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Channel selection now shares a weighted-index helper between database and memory-cache paths. Raw channel weights are used, zero-weight channels are excluded when positive weights exist, all-zero candidates are selected equally, and both behaviors are covered by tests.

Changes

Channel weight selection

Layer / File(s) Summary
Shared weighted selector
model/channel_weight.go, model/channel_weight_test.go
Adds validated weighted-index selection with overflow checks, equal selection for all-zero weights, and tests for weight intervals and empty inputs.
Database and cache integration
model/ability.go, model/channel_cache.go, model/channel_weight_test.go
Updates both channel-selection paths to use raw weights through the shared helper and verifies consistent behavior across database and memory-cache modes.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: calcium-ion

Poem

A rabbit hops through weights so neat,
Raw sums guide each channel’s feet.
Zero bows when positives call,
Equal chances share the ball.
One helper keeps the paths in tune!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement a shared weighted selector, matching the issue’s required raw-weight, all-zero, and zero-weight behavior.
Out of Scope Changes check ✅ Passed The PR stays focused on channel-weight selection logic and tests, with no clear unrelated feature work.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: unifying weighted channel selection across cache and database paths.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@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.

🧹 Nitpick comments (2)
model/channel_cache.go (2)

183-187: 🧹 Nitpick | 🔵 Trivial

Behavioral change worth calling out in release notes.

Zero-weight channels sharing a priority tier with any positive-weight channel will now receive zero traffic (previously the smoothed algorithm gave them some). This is the intended fix, but operators relying on the old "slow trickle" behavior for zero-weight channels (e.g., soft-disabling without a hard cutoff) should be informed via changelog/migration notes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@model/channel_cache.go` around lines 183 - 187, Update the release notes or
migration documentation for the channel selection behavior around
selectWeightedIndex: document that zero-weight channels in a priority tier
containing positive-weight channels now receive no traffic, and warn operators
that the previous slow-trickle soft-disable behavior no longer applies.

162-172: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use Channel.GetWeight() instead of duplicating the nil-default here.

Channel.GetWeight() already returns 0 when Weight is nil, so assigning the local uint(0) and manually dereferencing Weight duplicates logic that should go only through the accessor.

♻️ Suggested consolidation
-				weight := uint(0)
-				if channel.Weight != nil {
-					weight = *channel.Weight
-				}
-				targetChannels = append(targetChannels, channel)
-				targetWeights = append(targetWeights, weight)
+				targetChannels = append(targetChannels, channel)
+				targetWeights = append(targetWeights, uint(channel.GetWeight()))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@model/channel_cache.go` around lines 162 - 172, In the channel filtering
loop, replace the local nil-safe weight initialization and manual Weight
dereference with the existing Channel.GetWeight() accessor when appending to
targetWeights. Keep the targetChannels and priority filtering behavior
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@model/channel_cache.go`:
- Around line 183-187: Update the release notes or migration documentation for
the channel selection behavior around selectWeightedIndex: document that
zero-weight channels in a priority tier containing positive-weight channels now
receive no traffic, and warn operators that the previous slow-trickle
soft-disable behavior no longer applies.
- Around line 162-172: In the channel filtering loop, replace the local nil-safe
weight initialization and manual Weight dereference with the existing
Channel.GetWeight() accessor when appending to targetWeights. Keep the
targetChannels and priority filtering behavior unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d797e05a-2070-409e-9c5b-ef75d34d471f

📥 Commits

Reviewing files that changed from the base of the PR and between 66ee6b8 and fd8beaf.

📒 Files selected for processing (4)
  • model/ability.go
  • model/channel_cache.go
  • model/channel_weight.go
  • model/channel_weight_test.go

@faithleysath

Copy link
Copy Markdown
Contributor Author

已核对 CodeRabbit 的两个 nit:

  1. 已在 PR 描述中补充升级提示,明确同优先级池中存在正权重时,零权重渠道不再接收新流量。
  2. 保留 channel.Weight 的 nil-safe uint 读取,不改用 GetWeight()。后者返回 int,而持久化字段是 *uint;选择 helper 使用 uint/uint64 并显式检查求和溢出,避免在进入 helper 前缩窄为有符号整数。

因此本轮无需修改代码。

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.

[Bug] 内存缓存与数据库路径的渠道权重比例不一致(weight vs weight+10)

1 participant