mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
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:
@@ -18,6 +18,17 @@ pub trait UsageEventRecorder: Send + Sync {
|
||||
async fn record_usage_event(&self, event: &UsageEvent) -> Result<(), DataLayerError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait ManualProxyNodeCounter: Send + Sync {
|
||||
async fn increment_manual_proxy_node_requests(
|
||||
&self,
|
||||
node_id: &str,
|
||||
total_delta: i64,
|
||||
failed_delta: i64,
|
||||
latency_ms: Option<i64>,
|
||||
) -> Result<(), DataLayerError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait UsageRecordWriter: Send + Sync {
|
||||
async fn upsert_usage_record(
|
||||
@@ -39,7 +50,7 @@ impl<T> UsageDataEventRecorder<T> {
|
||||
#[async_trait]
|
||||
impl<T> UsageEventRecorder for UsageDataEventRecorder<T>
|
||||
where
|
||||
T: UsageRecordWriter + UsageSettlementWriter + Send + Sync,
|
||||
T: UsageRecordWriter + UsageSettlementWriter + ManualProxyNodeCounter + Send + Sync,
|
||||
{
|
||||
async fn record_usage_event(&self, event: &UsageEvent) -> Result<(), DataLayerError> {
|
||||
write_event_record(self.data.as_ref(), event).await
|
||||
@@ -198,22 +209,73 @@ pub fn build_usage_queue_worker<T>(
|
||||
config: UsageRuntimeConfig,
|
||||
) -> Result<UsageQueueWorker, DataLayerError>
|
||||
where
|
||||
T: UsageRecordWriter + UsageSettlementWriter + Send + Sync + 'static,
|
||||
T: UsageRecordWriter + UsageSettlementWriter + ManualProxyNodeCounter + Send + Sync + 'static,
|
||||
{
|
||||
UsageQueueWorker::new(runner, Arc::new(UsageDataEventRecorder::new(data)), config)
|
||||
}
|
||||
|
||||
pub async fn write_event_record<T>(data: &T, event: &UsageEvent) -> Result<(), DataLayerError>
|
||||
where
|
||||
T: UsageRecordWriter + UsageSettlementWriter + Send + Sync,
|
||||
T: UsageRecordWriter + UsageSettlementWriter + ManualProxyNodeCounter + Send + Sync,
|
||||
{
|
||||
let record = build_upsert_usage_record_from_event(event)?;
|
||||
if let Some(stored) = data.upsert_usage_record(record).await? {
|
||||
settle_usage_if_needed(data, &stored).await?;
|
||||
}
|
||||
increment_manual_proxy_node_from_event(data, event).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn increment_manual_proxy_node_from_event<T>(data: &T, event: &UsageEvent)
|
||||
where
|
||||
T: ManualProxyNodeCounter + Send + Sync,
|
||||
{
|
||||
let is_terminal = matches!(
|
||||
event.event_type,
|
||||
crate::UsageEventType::Completed | crate::UsageEventType::Failed
|
||||
);
|
||||
if !is_terminal {
|
||||
return;
|
||||
}
|
||||
let Some(node_id) = extract_manual_proxy_node_id(event) else {
|
||||
return;
|
||||
};
|
||||
let failed = matches!(event.event_type, crate::UsageEventType::Failed);
|
||||
let failed_delta = if failed { 1i64 } else { 0i64 };
|
||||
let latency_ms = event.data.response_time_ms.map(|v| v as i64);
|
||||
if let Err(err) = data
|
||||
.increment_manual_proxy_node_requests(&node_id, 1, failed_delta, latency_ms)
|
||||
.await
|
||||
{
|
||||
warn!(
|
||||
event_name = "manual_proxy_node_increment_failed",
|
||||
log_type = "ops",
|
||||
node_id = %node_id,
|
||||
error = ?err,
|
||||
"failed to increment manual proxy node request count"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_manual_proxy_node_id(event: &UsageEvent) -> Option<String> {
|
||||
let metadata = event.data.request_metadata.as_ref()?;
|
||||
let proxy = metadata.get("proxy")?.as_object()?;
|
||||
let mode = proxy
|
||||
.get("mode")
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.unwrap_or("")
|
||||
.trim();
|
||||
if mode == "tunnel" {
|
||||
return None;
|
||||
}
|
||||
proxy
|
||||
.get("node_id")
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|v| !v.is_empty())
|
||||
.map(String::from)
|
||||
}
|
||||
|
||||
fn consumer_name() -> String {
|
||||
let host = std::env::var("HOSTNAME")
|
||||
.ok()
|
||||
@@ -233,7 +295,7 @@ mod tests {
|
||||
use aether_data_contracts::repository::usage::{StoredRequestUsageAudit, UpsertUsageRecord};
|
||||
use async_trait::async_trait;
|
||||
|
||||
use super::{write_event_record, UsageRecordWriter};
|
||||
use super::{write_event_record, ManualProxyNodeCounter, UsageRecordWriter};
|
||||
use crate::{UsageEvent, UsageEventData, UsageEventType, UsageSettlementWriter};
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -317,6 +379,19 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ManualProxyNodeCounter for TestUsageStore {
|
||||
async fn increment_manual_proxy_node_requests(
|
||||
&self,
|
||||
_node_id: &str,
|
||||
_total_delta: i64,
|
||||
_failed_delta: i64,
|
||||
_latency_ms: Option<i64>,
|
||||
) -> Result<(), aether_data_contracts::DataLayerError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn sample_event() -> UsageEvent {
|
||||
UsageEvent::new(
|
||||
UsageEventType::Completed,
|
||||
|
||||
Reference in New Issue
Block a user