mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-25 13:45:03 +08:00
perf(proxy): trim per-request hot-path work and db wait
- Guard debug body serialization with `log::log_enabled!`; previously
serialized the filtered body to a throwaway String on every forward,
even with debug logging off.
- Skip SSE parse + UTF-8 buffer loop when no usage collector and debug
is off; the per-chunk `serde_json::from_str::<Value>` ran even in
pure passthrough mode.
- Add cheap per-app SSE event pre-filter (string `contains`) so usage
collectors only parse events that could contain usage (e.g. Claude
`message_start` / `message_delta`).
- Skip non-streaming response body JSON parse when usage logging is
disabled.
- Move `ProviderRouter::record_result` off the success response path
via `tokio::spawn` for non-HalfOpen state; that call internally does
`get_proxy_config_for_app` + `update_provider_health`, two SQLite
ops that previously blocked TTFB.
Also: dedupe `usage_logging_enabled` (was duplicated in handlers.rs)
and merge `SseUsageCollector::{new, new_filtered}` into a single
constructor that takes `Option<StreamUsageEventFilter>`.
This commit is contained in:
@@ -14,6 +14,12 @@ pub type ResponseUsageParser = fn(&Value) -> Option<TokenUsage>;
|
||||
/// 参数: (流式事件列表, 请求中的模型名称) -> 最终使用的模型名称
|
||||
pub type StreamModelExtractor = fn(&[Value], &str) -> String;
|
||||
|
||||
/// 流式 usage 事件预过滤器类型别名。
|
||||
///
|
||||
/// 参数是 SSE `data:` 原始字符串。返回 false 时跳过 JSON parse,避免在
|
||||
/// token/chunk 高频路径上解析与 usage 无关的事件。
|
||||
pub type StreamUsageEventFilter = fn(&str) -> bool;
|
||||
|
||||
/// 各 API 的使用量解析配置
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct UsageParserConfig {
|
||||
@@ -23,10 +29,32 @@ pub struct UsageParserConfig {
|
||||
pub response_parser: ResponseUsageParser,
|
||||
/// 流式响应中的模型提取器
|
||||
pub model_extractor: StreamModelExtractor,
|
||||
/// 流式 usage 事件预过滤器
|
||||
pub stream_event_filter: Option<StreamUsageEventFilter>,
|
||||
/// 应用类型字符串(用于日志记录)
|
||||
pub app_type_str: &'static str,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 流式 usage 事件预过滤
|
||||
// ============================================================================
|
||||
|
||||
pub fn claude_stream_usage_event_filter(data: &str) -> bool {
|
||||
data.contains("\"message_start\"") || data.contains("\"message_delta\"")
|
||||
}
|
||||
|
||||
fn openai_stream_usage_event_filter(data: &str) -> bool {
|
||||
data.contains("\"usage\"")
|
||||
}
|
||||
|
||||
fn codex_stream_usage_event_filter(data: &str) -> bool {
|
||||
data.contains("\"response.completed\"") || data.contains("\"usage\"")
|
||||
}
|
||||
|
||||
fn gemini_stream_usage_event_filter(data: &str) -> bool {
|
||||
data.contains("\"usageMetadata\"")
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 模型提取器实现
|
||||
// ============================================================================
|
||||
@@ -104,6 +132,7 @@ pub const CLAUDE_PARSER_CONFIG: UsageParserConfig = UsageParserConfig {
|
||||
stream_parser: TokenUsage::from_claude_stream_events,
|
||||
response_parser: TokenUsage::from_claude_response,
|
||||
model_extractor: claude_model_extractor,
|
||||
stream_event_filter: Some(claude_stream_usage_event_filter),
|
||||
app_type_str: "claude",
|
||||
};
|
||||
|
||||
@@ -112,6 +141,7 @@ pub const OPENAI_PARSER_CONFIG: UsageParserConfig = UsageParserConfig {
|
||||
stream_parser: TokenUsage::from_openai_stream_events,
|
||||
response_parser: TokenUsage::from_openai_response,
|
||||
model_extractor: openai_model_extractor,
|
||||
stream_event_filter: Some(openai_stream_usage_event_filter),
|
||||
app_type_str: "codex",
|
||||
};
|
||||
|
||||
@@ -120,6 +150,7 @@ pub const CODEX_PARSER_CONFIG: UsageParserConfig = UsageParserConfig {
|
||||
stream_parser: TokenUsage::from_codex_stream_events_auto,
|
||||
response_parser: TokenUsage::from_codex_response_auto,
|
||||
model_extractor: codex_auto_model_extractor,
|
||||
stream_event_filter: Some(codex_stream_usage_event_filter),
|
||||
app_type_str: "codex",
|
||||
};
|
||||
|
||||
@@ -128,6 +159,7 @@ pub const GEMINI_PARSER_CONFIG: UsageParserConfig = UsageParserConfig {
|
||||
stream_parser: TokenUsage::from_gemini_stream_chunks,
|
||||
response_parser: TokenUsage::from_gemini_response,
|
||||
model_extractor: gemini_model_extractor,
|
||||
stream_event_filter: Some(gemini_stream_usage_event_filter),
|
||||
app_type_str: "gemini",
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user