fix(gateway): 修复 balance 刷新去重键冲突、usage 状态回退与测试竞态

- balance_cache: 引入实例级 refresh key 防止多实例共享进程级 HashSet 冲突
- InMemoryUsageRepo: 阻止 pending/streaming 状态覆盖已终结(completed/failed/cancelled)记录
- usage 同步测试: 等待条件从 is_some() 改为检查 status=="completed" 避免竞态
- wallet 测试: 增加轮询等待 wallet 扣款完成
- 整理 import 语句与 tests 模块位置
This commit is contained in:
fawney19
2026-04-13 16:48:05 +08:00
parent 9a376e4223
commit 4fd2b4a014
13 changed files with 266 additions and 70 deletions

View File

@@ -4,4 +4,5 @@ mod filters;
pub(super) use aggregations::admin_usage_aggregation_by_user_json;
pub(super) use cache_affinity::list_recent_completed_usage_for_cache_affinity;
pub(super) use filters::{admin_usage_api_key_names, admin_usage_provider_key_names};
pub(super) use filters::admin_usage_api_key_names;
pub(super) use filters::admin_usage_provider_key_names;

View File

@@ -1,4 +1,5 @@
use super::analytics::{admin_usage_api_key_names, admin_usage_provider_key_names};
use super::analytics::admin_usage_api_key_names;
use super::analytics::admin_usage_provider_key_names;
use super::replay::{
admin_usage_curl_headers, admin_usage_curl_url, admin_usage_headers_from_value,
admin_usage_id_from_action_path, admin_usage_id_from_detail_path,

View File

@@ -107,40 +107,6 @@ pub(super) fn build_admin_usage_curl_response(
)
}
#[cfg(test)]
mod tests {
use super::admin_usage_body_value_from_sources;
use serde_json::json;
#[test]
fn resolved_reference_body_wins_over_inline_fallback() {
let inline_body = json!({
"truncated": true,
"reason": "usage_capture_limits_exceeded"
});
let ref_body = json!({
"messages": [{"role": "user", "content": "real request body"}]
});
assert_eq!(
admin_usage_body_value_from_sources(Some(ref_body.clone()), Some(&inline_body)),
Some(ref_body)
);
}
#[test]
fn inline_body_is_used_when_reference_body_is_unavailable() {
let inline_body = json!({
"messages": [{"role": "user", "content": "fallback inline body"}]
});
assert_eq!(
admin_usage_body_value_from_sources(None, Some(&inline_body)),
Some(inline_body)
);
}
}
pub(super) fn build_admin_usage_detail_payload(
item: &StoredRequestUsageAudit,
users_by_id: &BTreeMap<String, aether_data::repository::users::StoredUserSummary>,
@@ -415,3 +381,37 @@ pub(super) fn admin_usage_build_curl_command(
) -> String {
aether_admin::observability::usage::admin_usage_build_curl_command(url, headers, body)
}
#[cfg(test)]
mod tests {
use super::admin_usage_body_value_from_sources;
use serde_json::json;
#[test]
fn resolved_reference_body_wins_over_inline_fallback() {
let inline_body = json!({
"truncated": true,
"reason": "usage_capture_limits_exceeded"
});
let ref_body = json!({
"messages": [{"role": "user", "content": "real request body"}]
});
assert_eq!(
admin_usage_body_value_from_sources(Some(ref_body.clone()), Some(&inline_body)),
Some(ref_body)
);
}
#[test]
fn inline_body_is_used_when_reference_body_is_unavailable() {
let inline_body = json!({
"messages": [{"role": "user", "content": "fallback inline body"}]
});
assert_eq!(
admin_usage_body_value_from_sources(None, Some(&inline_body)),
Some(inline_body)
);
}
}

View File

@@ -1,5 +1,6 @@
use super::super::stats::{AdminStatsTimeRange, AdminStatsUsageFilter};
use super::analytics::{admin_usage_api_key_names, admin_usage_provider_key_names};
use super::analytics::admin_usage_api_key_names;
use super::analytics::admin_usage_provider_key_names;
use crate::handlers::admin::request::{AdminAppState, AdminRequestContext};
use crate::handlers::admin::shared::query_param_value;
use crate::GatewayError;