mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 09:20:22 +08:00
fix(usage): 修复含失败信号的 pending 请求被误判为活跃的问题
- pending/streaming 状态含 status_code >= 400 或 error_message 时视为 failed - 候选状态派生改为 failed 优先于 stale pending/streaming - 活跃请求轮询时保留失败信号字段的更新 - 图片流支持 partial_image 事件转发及从 response.completed 读取最终图片
This commit is contained in:
@@ -227,15 +227,21 @@ pub fn admin_usage_matches_api_format(
|
||||
}
|
||||
|
||||
pub fn admin_usage_is_failed(item: &StoredRequestUsageAudit) -> bool {
|
||||
let status = item.status.trim();
|
||||
if !status.is_empty() {
|
||||
return status.eq_ignore_ascii_case("failed");
|
||||
}
|
||||
item.status_code.is_some_and(|value| value >= 400)
|
||||
let has_failure_signal = item.status_code.is_some_and(|value| value >= 400)
|
||||
|| item
|
||||
.error_message
|
||||
.as_deref()
|
||||
.is_some_and(|value| !value.trim().is_empty())
|
||||
.is_some_and(|value| !value.trim().is_empty());
|
||||
let status = item.status.trim().to_ascii_lowercase();
|
||||
if !status.is_empty() {
|
||||
return match status.as_str() {
|
||||
"completed" | "cancelled" => false,
|
||||
"pending" | "streaming" => has_failure_signal,
|
||||
"failed" => true,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
has_failure_signal
|
||||
}
|
||||
|
||||
pub fn admin_usage_has_fallback(item: &StoredRequestUsageAudit) -> bool {
|
||||
@@ -588,6 +594,8 @@ fn admin_usage_active_request_json(
|
||||
"actual_cost": round_to(item.actual_total_cost_usd, 6),
|
||||
"response_time_ms": item.response_time_ms,
|
||||
"first_byte_time_ms": item.first_byte_time_ms,
|
||||
"status_code": item.status_code,
|
||||
"error_message": item.error_message,
|
||||
"provider": item.provider_name,
|
||||
"api_key_name": api_key_name,
|
||||
"provider_key_name": provider_key_name,
|
||||
@@ -2093,6 +2101,14 @@ mod tests {
|
||||
assert!(admin_usage_matches_status(&item, Some("failed")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn active_status_with_failure_signal_counts_as_failed() {
|
||||
let item = sample_usage("pending", Some(503), Some("upstream failed"));
|
||||
|
||||
assert!(admin_usage_is_failed(&item));
|
||||
assert!(admin_usage_matches_status(&item, Some("failed")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn admin_usage_fallback_flag_uses_routing_candidate_index() {
|
||||
let mut item = sample_usage("completed", Some(200), None);
|
||||
|
||||
@@ -269,6 +269,20 @@ pub fn derive_request_candidate_final_status(
|
||||
return RequestCandidateFinalStatus::Success;
|
||||
}
|
||||
|
||||
let has_failed = candidates
|
||||
.iter()
|
||||
.any(|candidate| candidate.status == RequestCandidateStatus::Failed);
|
||||
if has_failed {
|
||||
return RequestCandidateFinalStatus::Failed;
|
||||
}
|
||||
|
||||
let has_cancelled = candidates
|
||||
.iter()
|
||||
.any(|candidate| candidate.status == RequestCandidateStatus::Cancelled);
|
||||
if has_cancelled {
|
||||
return RequestCandidateFinalStatus::Cancelled;
|
||||
}
|
||||
|
||||
if candidates
|
||||
.iter()
|
||||
.any(|candidate| candidate.status == RequestCandidateStatus::Streaming)
|
||||
@@ -283,16 +297,6 @@ pub fn derive_request_candidate_final_status(
|
||||
return RequestCandidateFinalStatus::Pending;
|
||||
}
|
||||
|
||||
let has_cancelled = candidates
|
||||
.iter()
|
||||
.any(|candidate| candidate.status == RequestCandidateStatus::Cancelled);
|
||||
let has_failed = candidates
|
||||
.iter()
|
||||
.any(|candidate| candidate.status == RequestCandidateStatus::Failed);
|
||||
if has_cancelled && !has_failed {
|
||||
return RequestCandidateFinalStatus::Cancelled;
|
||||
}
|
||||
|
||||
RequestCandidateFinalStatus::Failed
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user