mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
feat(observability): 引入错误链路 error_flow 元数据并区分上游/客户端错误
- 网关在本地 failover 时构建 error_flow 元数据(分类/决策/传播策略),写入 report_context - scheduler-core 解析并透传 error_flow 至候选 extra_data - admin usage 详情拆分 request/upstream/client/failure_summary 错误域,敏感上游错误标记为 suppressed - 前端 RequestDetailDrawer 拆出"返回客户端"与"上游响应"双错误卡片 - HorizontalRequestTimeline 节点详情展示真实请求错误及 error_flow 标签
This commit is contained in:
@@ -23,6 +23,7 @@ pub struct SchedulerRequestCandidateReportContext {
|
||||
pub header_rules: Option<Value>,
|
||||
pub body_rules: Option<Value>,
|
||||
pub proxy: Option<Value>,
|
||||
pub error_flow: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
@@ -47,6 +48,19 @@ pub struct SchedulerExecutionRequestCandidateSeed {
|
||||
pub report_context: Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct ReportCandidateExtraDataInput {
|
||||
client_api_format: Option<String>,
|
||||
provider_api_format: Option<String>,
|
||||
upstream_url: Option<String>,
|
||||
mapped_model: Option<String>,
|
||||
key_name: Option<String>,
|
||||
header_rules: Option<Value>,
|
||||
body_rules: Option<Value>,
|
||||
proxy: Option<Value>,
|
||||
error_flow: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct SchedulerRequestCandidateStatusUpdate {
|
||||
pub status: RequestCandidateStatus,
|
||||
@@ -123,6 +137,10 @@ pub fn parse_request_candidate_report_context(
|
||||
.get("proxy")
|
||||
.cloned()
|
||||
.filter(|value| !value.is_null()),
|
||||
error_flow: report_context
|
||||
.get("error_flow")
|
||||
.cloned()
|
||||
.filter(|value| !value.is_null()),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -151,6 +169,7 @@ pub fn resolve_report_request_candidate_slot(
|
||||
header_rules,
|
||||
body_rules,
|
||||
proxy,
|
||||
error_flow,
|
||||
} = metadata;
|
||||
let request_id = request_id?;
|
||||
let synthesized_extra_data = build_report_candidate_extra_data(ReportCandidateExtraDataInput {
|
||||
@@ -162,6 +181,7 @@ pub fn resolve_report_request_candidate_slot(
|
||||
header_rules,
|
||||
body_rules,
|
||||
proxy,
|
||||
error_flow,
|
||||
});
|
||||
let created_at_unix_ms = matched_candidate
|
||||
.as_ref()
|
||||
@@ -325,6 +345,7 @@ pub fn build_local_request_candidate_status_record(
|
||||
header_rules: metadata.header_rules.clone(),
|
||||
body_rules: metadata.body_rules.clone(),
|
||||
proxy: metadata.proxy.clone(),
|
||||
error_flow: metadata.error_flow.clone(),
|
||||
});
|
||||
let created_at_unix_ms = started_at_unix_ms.or(finished_at_unix_ms);
|
||||
|
||||
@@ -526,17 +547,6 @@ fn next_candidate_index(candidates: &[StoredRequestCandidate]) -> u32 {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
struct ReportCandidateExtraDataInput {
|
||||
client_api_format: Option<String>,
|
||||
provider_api_format: Option<String>,
|
||||
upstream_url: Option<String>,
|
||||
mapped_model: Option<String>,
|
||||
key_name: Option<String>,
|
||||
header_rules: Option<Value>,
|
||||
body_rules: Option<Value>,
|
||||
proxy: Option<Value>,
|
||||
}
|
||||
|
||||
fn build_report_candidate_extra_data(input: ReportCandidateExtraDataInput) -> Option<Value> {
|
||||
let ReportCandidateExtraDataInput {
|
||||
client_api_format,
|
||||
@@ -547,6 +557,7 @@ fn build_report_candidate_extra_data(input: ReportCandidateExtraDataInput) -> Op
|
||||
header_rules,
|
||||
body_rules,
|
||||
proxy,
|
||||
error_flow,
|
||||
} = input;
|
||||
let mut extra_data = Map::with_capacity(8);
|
||||
extra_data.insert("gateway_execution_runtime".to_string(), Value::Bool(true));
|
||||
@@ -581,6 +592,9 @@ fn build_report_candidate_extra_data(input: ReportCandidateExtraDataInput) -> Op
|
||||
if let Some(proxy) = proxy {
|
||||
extra_data.insert("proxy".to_string(), proxy);
|
||||
}
|
||||
if let Some(error_flow) = error_flow {
|
||||
extra_data.insert("error_flow".to_string(), error_flow);
|
||||
}
|
||||
(!extra_data.is_empty()).then_some(Value::Object(extra_data))
|
||||
}
|
||||
|
||||
@@ -729,6 +743,11 @@ mod tests {
|
||||
"node_id": "proxy-node-1",
|
||||
"node_name": "edge-1",
|
||||
"source": "provider"
|
||||
},
|
||||
"error_flow": {
|
||||
"classification": "retry_upstream_failure",
|
||||
"decision": "retry_next_candidate",
|
||||
"propagation": "suppressed"
|
||||
}
|
||||
})))
|
||||
.expect("metadata");
|
||||
@@ -777,6 +796,13 @@ mod tests {
|
||||
.map(Vec::len),
|
||||
Some(1)
|
||||
);
|
||||
assert_eq!(
|
||||
slot.extra_data
|
||||
.as_ref()
|
||||
.and_then(|value| value.get("error_flow"))
|
||||
.and_then(|value| value.get("propagation")),
|
||||
Some(&json!("suppressed"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user