mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-31 11:01:36 +08:00
refactor(proxy): extract handle_rectifier_retry_failure helper
The signature (RECT-003) and budget (RECT-012) rectifier branches each
carried ~50 lines of identical "provider error -> record + continue /
client error -> release permit + return" handling. The only piece that
varied between them was a log label ("整流" vs "budget 整流").
Move the shared logic into RequestForwarder::handle_rectifier_retry_failure
that returns Option<ForwardError> — None means "continue to the next
provider", Some(err) means "terminal failure, return to the client".
Each call site shrinks from ~50 lines to ~17, drops one level of
indentation, and the two branches now provably cannot drift apart.
forwarder.rs nets ~40 lines smaller.
This commit is contained in:
@@ -154,6 +154,70 @@ impl RequestForwarder {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 整流(thinking signature 或 budget)重试失败后的统一收尾。
|
||||||
|
///
|
||||||
|
/// `None` 表示已记录熔断器、累积 `last_error`/`last_provider`,
|
||||||
|
/// 调用方应 `continue` 让下一家 provider 继续故障转移;
|
||||||
|
/// `Some(ForwardError)` 表示是客户端错误,没有 provider 能修复,
|
||||||
|
/// 调用方应直接 `return` 把错误返回给客户端。
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
async fn handle_rectifier_retry_failure(
|
||||||
|
&self,
|
||||||
|
retry_err: ProxyError,
|
||||||
|
provider: &Provider,
|
||||||
|
app_type_str: &str,
|
||||||
|
used_half_open_permit: bool,
|
||||||
|
rectifier_label: &str,
|
||||||
|
last_error: &mut Option<ProxyError>,
|
||||||
|
last_provider: &mut Option<Provider>,
|
||||||
|
) -> Option<ForwardError> {
|
||||||
|
// Provider 错误:本家上游/网络确实出问题,下一家 provider 可能可用 → 继续故障转移。
|
||||||
|
// 客户端错误:整流后请求仍违法,下一家也修不好 → 直接返回。
|
||||||
|
let is_provider_error = match &retry_err {
|
||||||
|
ProxyError::Timeout(_) | ProxyError::ForwardFailed(_) => true,
|
||||||
|
ProxyError::UpstreamError { status, .. } => *status >= 500,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_provider_error {
|
||||||
|
let _ = self
|
||||||
|
.router
|
||||||
|
.record_result(
|
||||||
|
&provider.id,
|
||||||
|
app_type_str,
|
||||||
|
used_half_open_permit,
|
||||||
|
false,
|
||||||
|
Some(retry_err.to_string()),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
{
|
||||||
|
let mut status = self.status.write().await;
|
||||||
|
status.last_error = Some(format!(
|
||||||
|
"Provider {} {rectifier_label}重试失败: {}",
|
||||||
|
provider.name, retry_err
|
||||||
|
));
|
||||||
|
}
|
||||||
|
*last_error = Some(retry_err);
|
||||||
|
*last_provider = Some(provider.clone());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.router
|
||||||
|
.release_permit_neutral(&provider.id, app_type_str, used_half_open_permit)
|
||||||
|
.await;
|
||||||
|
let mut status = self.status.write().await;
|
||||||
|
status.failed_requests += 1;
|
||||||
|
status.last_error = Some(retry_err.to_string());
|
||||||
|
if status.total_requests > 0 {
|
||||||
|
status.success_rate =
|
||||||
|
(status.success_requests as f32 / status.total_requests as f32) * 100.0;
|
||||||
|
}
|
||||||
|
Some(ForwardError {
|
||||||
|
error: retry_err,
|
||||||
|
provider: Some(provider.clone()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// 转发请求(带故障转移)
|
/// 转发请求(带故障转移)
|
||||||
///
|
///
|
||||||
/// 这是 thin wrapper:在客户端请求维度记一次 `total_requests` / 调整
|
/// 这是 thin wrapper:在客户端请求维度记一次 `total_requests` / 调整
|
||||||
@@ -486,67 +550,24 @@ impl RequestForwarder {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
Err(retry_err) => {
|
Err(retry_err) => {
|
||||||
// 整流重试仍失败:区分错误类型
|
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"[{app_type_str}] [RECT-003] 整流重试仍失败: {retry_err}"
|
"[{app_type_str}] [RECT-003] 整流重试仍失败: {retry_err}"
|
||||||
);
|
);
|
||||||
|
if let Some(err) = self
|
||||||
// Provider 错误 vs 客户端错误:Provider 错误说明本家
|
.handle_rectifier_retry_failure(
|
||||||
// 上游有问题,下一家 provider 可能可用,应当继续故障转移;
|
retry_err,
|
||||||
// 客户端错误说明整流后的请求本身就有问题,下一家也修不好。
|
provider,
|
||||||
let is_provider_error = match &retry_err {
|
|
||||||
ProxyError::Timeout(_)
|
|
||||||
| ProxyError::ForwardFailed(_) => true,
|
|
||||||
ProxyError::UpstreamError { status, .. } => {
|
|
||||||
*status >= 500
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if is_provider_error {
|
|
||||||
// Provider 问题:记录熔断器后继续轮询下一家
|
|
||||||
let _ = self
|
|
||||||
.router
|
|
||||||
.record_result(
|
|
||||||
&provider.id,
|
|
||||||
app_type_str,
|
|
||||||
used_half_open_permit,
|
|
||||||
false,
|
|
||||||
Some(retry_err.to_string()),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
{
|
|
||||||
let mut status = self.status.write().await;
|
|
||||||
status.last_error = Some(format!(
|
|
||||||
"Provider {} 整流重试失败: {}",
|
|
||||||
provider.name, retry_err
|
|
||||||
));
|
|
||||||
}
|
|
||||||
last_error = Some(retry_err);
|
|
||||||
last_provider = Some(provider.clone());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 客户端问题:释放 permit 后直接返回,不再尝试其它 provider
|
|
||||||
self.router
|
|
||||||
.release_permit_neutral(
|
|
||||||
&provider.id,
|
|
||||||
app_type_str,
|
app_type_str,
|
||||||
used_half_open_permit,
|
used_half_open_permit,
|
||||||
|
"整流",
|
||||||
|
&mut last_error,
|
||||||
|
&mut last_provider,
|
||||||
)
|
)
|
||||||
.await;
|
.await
|
||||||
let mut status = self.status.write().await;
|
{
|
||||||
status.failed_requests += 1;
|
return Err(err);
|
||||||
status.last_error = Some(retry_err.to_string());
|
|
||||||
if status.total_requests > 0 {
|
|
||||||
status.success_rate = (status.success_requests as f32
|
|
||||||
/ status.total_requests as f32)
|
|
||||||
* 100.0;
|
|
||||||
}
|
}
|
||||||
return Err(ForwardError {
|
continue;
|
||||||
error: retry_err,
|
|
||||||
provider: Some(provider.clone()),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -690,59 +711,21 @@ impl RequestForwarder {
|
|||||||
log::warn!(
|
log::warn!(
|
||||||
"[{app_type_str}] [RECT-012] budget 整流重试仍失败: {retry_err}"
|
"[{app_type_str}] [RECT-012] budget 整流重试仍失败: {retry_err}"
|
||||||
);
|
);
|
||||||
|
if let Some(err) = self
|
||||||
// 与 signature 整流分支保持一致:provider 错误继续故障转移,
|
.handle_rectifier_retry_failure(
|
||||||
// 客户端错误直接返回。
|
retry_err,
|
||||||
let is_provider_error = match &retry_err {
|
provider,
|
||||||
ProxyError::Timeout(_) | ProxyError::ForwardFailed(_) => {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
ProxyError::UpstreamError { status, .. } => *status >= 500,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if is_provider_error {
|
|
||||||
let _ = self
|
|
||||||
.router
|
|
||||||
.record_result(
|
|
||||||
&provider.id,
|
|
||||||
app_type_str,
|
|
||||||
used_half_open_permit,
|
|
||||||
false,
|
|
||||||
Some(retry_err.to_string()),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
{
|
|
||||||
let mut status = self.status.write().await;
|
|
||||||
status.last_error = Some(format!(
|
|
||||||
"Provider {} budget 整流重试失败: {}",
|
|
||||||
provider.name, retry_err
|
|
||||||
));
|
|
||||||
}
|
|
||||||
last_error = Some(retry_err);
|
|
||||||
last_provider = Some(provider.clone());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.router
|
|
||||||
.release_permit_neutral(
|
|
||||||
&provider.id,
|
|
||||||
app_type_str,
|
app_type_str,
|
||||||
used_half_open_permit,
|
used_half_open_permit,
|
||||||
|
"budget 整流",
|
||||||
|
&mut last_error,
|
||||||
|
&mut last_provider,
|
||||||
)
|
)
|
||||||
.await;
|
.await
|
||||||
let mut status = self.status.write().await;
|
{
|
||||||
status.failed_requests += 1;
|
return Err(err);
|
||||||
status.last_error = Some(retry_err.to_string());
|
|
||||||
if status.total_requests > 0 {
|
|
||||||
status.success_rate = (status.success_requests as f32
|
|
||||||
/ status.total_requests as f32)
|
|
||||||
* 100.0;
|
|
||||||
}
|
}
|
||||||
return Err(ForwardError {
|
continue;
|
||||||
error: retry_err,
|
|
||||||
provider: Some(provider.clone()),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user