Skip to content

feat: 添加熔断机制全局设置与端点级免熔断开关并完善CI工作流 - #14

Closed
jiozhaoyue wants to merge 1 commit into
VkRainB:masterfrom
jiozhaoyue:feat/circuit-breaker-settings
Closed

jiozhaoyue wants to merge 1 commit into
VkRainB:masterfrom
jiozhaoyue:feat/circuit-breaker-settings

Conversation

@jiozhaoyue

Copy link
Copy Markdown

概述 / Overview

本 PR 为 ccMesh 引入了熔断机制全局配置化端点级免熔断控制,解决了此前熔断阈值硬编码(固定失败 4 次、冷却 60s)无法灵活调整的问题,并允许为内网/高可用稳定端点豁免熔断保护。同时补充并强化了上游 GitHub Actions CI 配置。


核心特性 / Features

  1. 全局熔断设置与平滑重载

    • 在「设置」页中新增「熔断保护」配置卡片。
    • 支持动态开启/关闭熔断、自定义连续失败阈值(150 次)及基础冷却时间(5600 秒)。
    • 修改设置后,运行中的代理服务会自动平滑重启(needs_restart 机制),无需手动启停。
  2. 端点级免熔断豁免

    • 在端点编辑弹窗的「高级」设置中新增「禁止熔断保护」开关。
    • 开启后遇到 5xx/429/网络超时时不进入熔断跳闸状态,始终保留在负载轮换候选列表中。
    • 端点列表中对免熔断端点展示醒目的「免熔断」Badge。
  3. CI 流程与质量门禁强化

    • .github/workflows/ci.yml 新增 pull_request: branches: [master] 触发器,覆盖 PR 提交审查。
    • 在跨平台 release 打包前,前置执行前端类型检查(pnpm check:front)、前端单元测试(pnpm test)与 Rust 类型检查(cargo check),快速拦截潜在错误。

变更明细 / Changes

  • 存储与迁移:
    • src-tauri/src/modules/storage/migration.rs: 新增 migration v19,为 endpoints 表追加 circuit_breaker_disabled INTEGER NOT NULL DEFAULT 0
    • src-tauri/src/modules/storage/config_repo.rs: 配置表支持 circuitBreakerEnabled, circuitBreakerFailureThreshold, circuitBreakerTimeout 读写。
    • src-tauri/src/commands/config.rs: 熔断配置键加入 needs_restart
  • 代理与状态机:
    • src-tauri/src/modules/proxy/circuit_breaker.rs: 新增 BreakerRegistry::from_options,全局禁用时 is_enabled() == false 绕过状态机,select_candidates 豁免免熔断端点。
    • src-tauri/src/modules/proxy/forward.rs: 对 circuit_breaker_disabled == true 的端点跳过 Gate 拦截与失败上报。
    • src-tauri/src/commands/health.rs: 免熔断端点健康状态始终报告为 circuit: "closed"
  • 前端页面与组件:
    • src/pages/Settings/_components/CircuitBreakerCard.tsx: 新建熔断保护设置卡片。
    • src/pages/Endpoints/_components/EndpointForm.tsx: 支持配置 circuitBreakerDisabled
    • src/pages/Endpoints/_components/EndpointCard.tsx: 渲染「免熔断」徽标。
  • 文档:
    • docs-site/advanced/rotation.md & docs/KB/patterns/circuit-breaker.md: 补充配置与单端点免熔断说明。

质量验证 / Verification

测试项 命令 结果
前端类型检查 pnpm check:front 0 错误
前端单元测试 pnpm test 27/27 文件,193/193 项通过
Rust 代码格式 cargo fmt -- --check 通过
Rust 编译检查 cargo check --message-format=short 通过 (0.59s)
数据库迁移单测 v19_adds_circuit_breaker_disabled_column 通过

兼容性说明 / Backward Compatibility

  • 数据库迁移采用增量 ADD COLUMN ... DEFAULT 0,老数据平滑升级,端点行为默认保持现有熔断规则。
  • 配置项设置默认缺省值(enabled=true, threshold=4, timeout=60),与原有默认行为 100% 保持一致。

@bolt-new-by-stackblitz

Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@jiozhaoyue
jiozhaoyue marked this pull request as ready for review September 12, 2026 12:15
Copilot AI lite review requested due to automatic review settings September 12, 2026 12:15
@jiozhaoyue jiozhaoyue closed this Sep 12, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Unresolved moderate issues affect validation, backup/restore persistence, and health-state refresh.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This PR adds configurable global circuit-breaker settings and endpoint-level bypass controls, plus persistence, proxy integration, documentation, and expanded CI validation.

Changes:

  • Adds configurable breaker enablement, thresholds, and cooldowns.
  • Adds endpoint bypass controls, badges, and health-state handling.
  • Adds database/config migration support and stronger PR CI checks.
File summaries
File Reviewed changes and final comments
src/services/modules/endpoint.ts Adds endpoint bypass types.
src/services/modules/config.ts Adds circuit-breaker configuration types.
src/pages/Settings/index.tsx Registers the breaker settings card.
src/pages/Settings/_components/CircuitBreakerCard.tsx Provides breaker controls. Moderate (3 votes): enforce the advertised maximum of 50 before saving; max validation alone allows out-of-range values. Applies at lines 37 and 56.
src/pages/Endpoints/_components/EndpointForm.tsx Adds the endpoint bypass control. Moderate (1 vote): refreshing only the endpoints query can leave cached dashboard breaker status stale after toggling the control.
src/pages/Endpoints/_components/EndpointCard.tsx Displays the bypass badge.
src-tauri/src/modules/storage/migration.rs Adds schema migration v19.
src-tauri/src/modules/storage/endpoint_repo.rs Persists endpoint bypass state.
src-tauri/src/modules/storage/config_repo.rs Reads and writes breaker settings. Moderate (2 votes): validate or reject threshold strings before conversion to u32, including negative and over-50 values. Moderate (3 votes): add the three breaker keys to MIGRATION_CONFIG_KEYS and related tests.
src-tauri/src/modules/proxy/server.rs Builds breakers from configuration.
src-tauri/src/modules/proxy/resolver.rs Updates endpoint test fixtures.
src-tauri/src/modules/proxy/inbound.rs Updates endpoint test fixtures.
src-tauri/src/modules/proxy/forward.rs Skips breaker handling for exempt endpoints.
src-tauri/src/modules/proxy/circuit_breaker.rs Adds configurable and disabled-registry behavior. Nit (1 vote): add regression coverage proving custom thresholds, timeouts, and Claude preset scaling reach the state machine. Moderate (1 vote): enforce the documented runtime ranges of 1–50 failures and 5–600 seconds.
src-tauri/src/modules/cc_switch_migration/importer.rs Initializes imported endpoints with breaker defaults.
src-tauri/src/models/endpoint.rs Adds endpoint bypass fields. Moderate (3 votes): include the field in export/restore DTOs, backup and WebDAV column lists, persistence operations, and tests.
src-tauri/src/models/config.rs Adds global breaker defaults.
src-tauri/src/commands/health.rs Reports exempt endpoints as closed.
src-tauri/src/commands/endpoint.rs Preserves bypass state when cloning endpoints.
src-tauri/src/commands/config.rs Restarts the proxy after breaker configuration changes. Moderate (1 vote): refresh endpoint health after changes so cards and dashboards do not retain stale Open/HalfOpen states.
src-tauri/Cargo.lock Updates package metadata.
docs/KB/patterns/circuit-breaker.md Documents breaker configuration and endpoint exemptions.
docs-site/advanced/rotation.md Documents global and endpoint settings.
.github/workflows/ci.yml Adds pull-request triggers and validation steps.
Review details

Suppressed comments (5)

src-tauri/src/commands/config.rs:45

  • 这些配置变更会重建并清空运行期熔断器,但 set_config 之后只发送代理状态事件;前端的端点健康查询只监听 endpoint-health-changed。因此关闭熔断或修改阈值/冷却时间后,卡片和仪表盘可能继续显示旧的 Open/HalfOpen 状态,直到下一次熔断状态转换。重启后应同时触发健康查询刷新。
            || patch.contains_key("circuitBreakerEnabled")
            || patch.contains_key("circuitBreakerFailureThreshold")
            || patch.contains_key("circuitBreakerTimeout");

src-tauri/src/modules/proxy/circuit_breaker.rs:306

  • This constructor is now the production path, but the added tests only call from_options(false, ...), which bypasses the configured threshold and timeout. There is no regression test proving that custom values (including the Claude preset scaling) reach the state machine, so these settings could silently fall back to defaults.
    pub fn from_options(enabled: bool, failure_threshold: u32, timeout_secs: u64) -> Self {

src-tauri/src/modules/proxy/circuit_breaker.rs:308

  • These bounds only apply a minimum, so values outside the advertised 1–50 failures and 5–600 seconds ranges are still accepted whenever they reach from_options (for example from persisted/synced config). Enforce the documented ranges here as a final runtime boundary; the UI max attributes are not sufficient.
        let ft = failure_threshold.max(1);
        let timeout = Duration::from_secs(timeout_secs.max(1));

src/pages/Endpoints/_components/EndpointForm.tsx:500

  • 切换此开关会触发 endpoints-changed,但现有事件处理只失效 endpoints 查询;仪表盘的 ServiceCard 仅依据缓存的 endpoint-health 判断熔断态。因此端点已免熔断后,若之前是 Open,仪表盘仍可能显示“熔断中”,直到发生另一条健康事件。请同时刷新健康查询,或让仪表盘状态判断尊重该字段。
                onCheckedChange={(v) => update({ circuitBreakerDisabled: v })}

src/pages/Settings/_components/CircuitBreakerCard.tsx:56

  • 冷却时间的处理同样只限制了下限,输入 601 秒以上仍会被持久化,和 UI/PR 声明的 5~600 秒范围不一致。请在保存前限制上限。
              const val = Math.max(5, parseInt(e.target.value, 10) || 60);
  • Files reviewed: 23/24 changed files
  • Comments generated: 4
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

#[serde(default)]
pub fast: bool,
#[serde(default)]
pub circuit_breaker_disabled: bool,
Comment on lines +30 to +32
"circuitBreakerEnabled",
"circuitBreakerFailureThreshold",
"circuitBreakerTimeout",
Comment on lines +103 to +107
circuit_breaker_failure_threshold: parse_i64(
&m,
"circuitBreakerFailureThreshold",
d.circuit_breaker_failure_threshold as i64,
) as u32,
disabled={!cfg.circuitBreakerEnabled}
defaultValue={cfg.circuitBreakerFailureThreshold ?? 4}
onBlur={(e) => {
const val = Math.max(1, parseInt(e.target.value, 10) || 4);
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