fix: 修复手动代理节点请求不计数及延迟/心跳不显示的问题 (#368)

* fix: 修复手动代理节点请求不计数及延迟/心跳不显示的问题

问题描述:
- 手动添加的代理节点请求数始终为0,不会递增
- 手动代理节点的延迟和最后心跳时间不显示

根因:
Rust 重写版中缺失了 Python 版的手动代理节点请求计数逻辑。
隧道节点通过心跳上报计数,但手动节点没有心跳机制,
需要在 usage recording 路径中递增计数并更新延迟信息。

修复方案:
1. 在 ExecutionPlan 中提取 proxy 信息,注入到 request_metadata
2. 在 request_metadata 白名单中添加 proxy 字段
3. 新增 INCREMENT_MANUAL_PROXY_NODE_REQUESTS_SQL,
   递增 total_requests/failed_requests,
   同时更新 avg_latency_ms 和 last_heartbeat_at
4. 在 ProxyNodeWriteRepository trait 新增 increment_manual_node_requests 方法
5. 在 write_event_record 中解析 request_metadata 中的 proxy 信息,
   对非隧道模式的手动节点调用递增方法
6. 为 GatewayDataState 实现 ManualProxyNodeCounter trait

影响范围:
- 仅影响手动代理节点的统计数据
- 隧道节点不受影响(继续通过心跳计数)
- 不影响请求转发逻辑

* style: cargo fmt

---------

Co-authored-by: root <root@ser406777952330.local>
This commit is contained in:
jiuwovo-ai
2026-05-03 14:50:36 +08:00
committed by GitHub
parent c4ea042eb4
commit 3e2eca4fd0
9 changed files with 195 additions and 9 deletions

View File

@@ -552,6 +552,32 @@ impl ProxyNodeWriteRepository for InMemoryProxyNodeRepository {
node.updated_at_unix_secs = Self::now_unix_secs();
Ok(Some(node.clone()))
}
async fn increment_manual_node_requests(
&self,
node_id: &str,
total_delta: i64,
failed_delta: i64,
latency_ms: Option<i64>,
) -> Result<(), DataLayerError> {
let mut nodes = self.nodes.write().expect("proxy node repository lock");
let Some(node) = nodes.get_mut(node_id) else {
return Ok(());
};
if !node.is_manual {
return Ok(());
}
if total_delta > 0 {
node.total_requests += total_delta;
}
if failed_delta > 0 {
node.failed_requests += failed_delta;
}
if let Some(ms) = latency_ms {
node.avg_latency_ms = Some(ms as f64);
}
Ok(())
}
}
#[cfg(test)]

View File

@@ -357,6 +357,18 @@ WHERE is_manual = FALSE
AND tunnel_connected = TRUE
"#;
const INCREMENT_MANUAL_PROXY_NODE_REQUESTS_SQL: &str = r#"
UPDATE proxy_nodes
SET
total_requests = total_requests + GREATEST($1::bigint, 0),
failed_requests = failed_requests + GREATEST($2::bigint, 0),
avg_latency_ms = COALESCE($3, avg_latency_ms),
last_heartbeat_at = NOW(),
updated_at = NOW()
WHERE id = $4
AND is_manual = TRUE
"#;
#[derive(Debug, Clone)]
pub struct SqlxProxyNodeRepository {
pool: PgPool,
@@ -986,6 +998,24 @@ VALUES (
self.find_proxy_node(&mutation.node_id).await
}
async fn increment_manual_node_requests(
&self,
node_id: &str,
total_delta: i64,
failed_delta: i64,
latency_ms: Option<i64>,
) -> Result<(), DataLayerError> {
sqlx::query(INCREMENT_MANUAL_PROXY_NODE_REQUESTS_SQL)
.bind(total_delta)
.bind(failed_delta)
.bind(latency_ms)
.bind(node_id)
.execute(&self.pool)
.await
.map_postgres_err()?;
Ok(())
}
}
#[cfg(test)]

View File

@@ -411,6 +411,14 @@ pub trait ProxyNodeWriteRepository: Send + Sync {
&self,
mutation: &ProxyNodeRemoteConfigMutation,
) -> Result<Option<StoredProxyNode>, crate::DataLayerError>;
async fn increment_manual_node_requests(
&self,
node_id: &str,
total_delta: i64,
failed_delta: i64,
latency_ms: Option<i64>,
) -> Result<(), crate::DataLayerError>;
}
#[cfg(test)]