fix(failover): patch P1-P3 reliability gaps surfaced by team review

- Forwarder buffers non-streaming bodies and primes streaming first
  chunk before signaling success, so body timeouts and SSE first-chunk
  failures route through the circuit breaker instead of being recorded
  as success on response-header arrival
- Atomic enable-failover: switch to P1 before persisting the flag, and
  roll back auto-added queue entries when the switch is rejected
  (e.g. official providers)
- Hot-reload circuit breaker config on per-app proxy config change
  instead of waiting for a proxy restart
- FailoverToggle / FailoverQueueManager / AutoFailoverConfigPanel
  require proxy takeover for the active app; the backend command also
  rejects enabling when takeover is off
- ProviderHealthBadge consumes the backend is_healthy flag instead of
  hardcoding the 5-failure threshold

Cleanup:
- impl From<&AppProxyConfig> for CircuitBreakerConfig and use it from
  the command layer
- Collapse three identical TabsContent blocks into a single map
This commit is contained in:
Jason
2026-05-14 21:35:02 +08:00
parent 940161fb0e
commit b642ef0633
14 changed files with 389 additions and 98 deletions
+17
View File
@@ -1993,6 +1993,23 @@ impl ProxyService {
Ok(())
}
/// 热更新指定应用的熔断器配置
pub async fn update_circuit_breaker_config_for_app(
&self,
app_type: &str,
config: crate::proxy::CircuitBreakerConfig,
) -> Result<(), String> {
if let Some(server) = self.server.read().await.as_ref() {
server
.update_circuit_breaker_config_for_app(app_type, config)
.await;
log::info!("已热更新 {app_type} 运行中的熔断器配置");
} else {
log::debug!("{app_type} 熔断器配置将在下次代理启动时生效");
}
Ok(())
}
/// 重置指定 Provider 的熔断器
///
/// 如果代理服务器正在运行,立即重置内存中的熔断器状态