mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-28 08:44:41 +08:00
fix(proxy): patch P0-P3 routing/lifecycle issues across forwarder paths
* stream_check: thread Result from get_auth_headers via map_err so the workspace builds again * forwarder: scope rectifier / budget-rectifier flags per-provider so failover can still apply rectification on the next attempt * forwarder: categorize before record_result; route NonRetryable and ClientAbort through release_permit_neutral so client-side failures don't pollute circuit breaker or DB health * handler_context: parse Gemini model from uri.path() and strip both ?query and :action verb defensively in extract_gemini_model_from_path * forwarder + response_processor + handlers: introduce ActiveConnectionGuard (RAII) so active_connections decrement covers the full streaming body lifetime, not just response headers * claude_desktop_config: use sort_by_key to clear the clippy gate
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
//! 统一处理流式和非流式 API 响应
|
||||
|
||||
use super::{
|
||||
forwarder::ActiveConnectionGuard,
|
||||
handler_config::{StreamUsageEventFilter, UsageParserConfig},
|
||||
handler_context::{RequestContext, StreamingTimeoutConfig},
|
||||
hyper_client::ProxyResponse,
|
||||
@@ -181,6 +182,7 @@ pub async fn handle_streaming(
|
||||
ctx: &RequestContext,
|
||||
state: &ProxyState,
|
||||
parser_config: &UsageParserConfig,
|
||||
connection_guard: Option<ActiveConnectionGuard>,
|
||||
) -> Response {
|
||||
let status = response.status();
|
||||
log::debug!(
|
||||
@@ -218,8 +220,13 @@ pub async fn handle_streaming(
|
||||
let timeout_config = ctx.streaming_timeout_config();
|
||||
|
||||
// 创建带日志和超时的透传流
|
||||
let logged_stream =
|
||||
create_logged_passthrough_stream(stream, ctx.tag, usage_collector, timeout_config);
|
||||
let logged_stream = create_logged_passthrough_stream(
|
||||
stream,
|
||||
ctx.tag,
|
||||
usage_collector,
|
||||
timeout_config,
|
||||
connection_guard,
|
||||
);
|
||||
|
||||
let body = axum::body::Body::from_stream(logged_stream);
|
||||
match builder.body(body) {
|
||||
@@ -237,6 +244,8 @@ pub async fn handle_non_streaming(
|
||||
ctx: &RequestContext,
|
||||
state: &ProxyState,
|
||||
parser_config: &UsageParserConfig,
|
||||
// guard 在函数 scope 内持有,整包响应读取完成后随函数返回一并 drop
|
||||
_connection_guard: Option<ActiveConnectionGuard>,
|
||||
) -> Result<Response, ProxyError> {
|
||||
// 整包超时:仅在故障转移开启且配置值非零时生效
|
||||
let body_timeout =
|
||||
@@ -339,11 +348,12 @@ pub async fn process_response(
|
||||
ctx: &RequestContext,
|
||||
state: &ProxyState,
|
||||
parser_config: &UsageParserConfig,
|
||||
connection_guard: Option<ActiveConnectionGuard>,
|
||||
) -> Result<Response, ProxyError> {
|
||||
if is_sse_response(&response) {
|
||||
Ok(handle_streaming(response, ctx, state, parser_config).await)
|
||||
Ok(handle_streaming(response, ctx, state, parser_config, connection_guard).await)
|
||||
} else {
|
||||
handle_non_streaming(response, ctx, state, parser_config).await
|
||||
handle_non_streaming(response, ctx, state, parser_config, connection_guard).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -631,8 +641,10 @@ pub fn create_logged_passthrough_stream(
|
||||
tag: &'static str,
|
||||
usage_collector: Option<SseUsageCollector>,
|
||||
timeout_config: StreamingTimeoutConfig,
|
||||
connection_guard: Option<ActiveConnectionGuard>,
|
||||
) -> impl Stream<Item = Result<Bytes, std::io::Error>> + Send {
|
||||
async_stream::stream! {
|
||||
let _conn_guard = connection_guard;
|
||||
let mut buffer = String::new();
|
||||
let mut utf8_remainder: Vec<u8> = Vec::new();
|
||||
let mut collector = usage_collector;
|
||||
|
||||
Reference in New Issue
Block a user