perf(usage): user-me usage 查询避免全量加载,默认限制 7 天范围

- UsageAuditListQuery 新增 limit 字段,支持在 SQL 层 LIMIT
- user-me usage 端点无时间范围时默认查最近 7 天
- active usage 端点无 ids 过滤时限制查最近 1 小时
- InMemory 实现同步支持 limit truncate
This commit is contained in:
fawney19
2026-04-15 16:25:57 +08:00
parent fbb8249c0d
commit 43e7ad112f
8 changed files with 37 additions and 2 deletions

View File

@@ -26,6 +26,7 @@ pub(crate) async fn list_usage_for_range(
provider_name: filters.provider_name.clone(),
model: filters.model.clone(),
statuses: None,
limit: None,
})
.await
}
@@ -46,6 +47,7 @@ pub(crate) async fn list_usage_for_optional_range(
provider_name: filters.provider_name.clone(),
model: filters.model.clone(),
statuses: None,
limit: None,
})
.await
}

View File

@@ -17,6 +17,7 @@ pub(in super::super) async fn list_recent_completed_usage_for_cache_affinity(
provider_name: None,
model: None,
statuses: None,
limit: None,
})
.await?;
items.retain(|item| item.status == "completed");

View File

@@ -486,6 +486,7 @@ async fn dashboard_list_usage_for_range(
provider_name: None,
model: None,
statuses: None,
limit: None,
})
.await
{
@@ -1215,6 +1216,7 @@ pub(super) async fn handle_dashboard_provider_status_get(
provider_name: None,
model: None,
statuses: None,
limit: None,
})
.await
{

View File

@@ -690,9 +690,22 @@ pub(super) async fn handle_users_me_usage_get(
Err(detail) => return admin_stats_bad_request_response(detail),
};
// When no time range is specified, default to 7 days to avoid full-table scans.
let effective_time_range = time_range.or_else(|| {
let today = Utc::now().date_naive();
let start_date = today
.checked_sub_signed(chrono::Duration::days(6))
.unwrap_or(today);
Some(AdminStatsTimeRange {
start_date,
end_date: today,
tz_offset_minutes: 0,
})
});
let usage = match list_usage_for_optional_range(
&AdminAppState::new(state),
time_range.as_ref(),
effective_time_range.as_ref(),
&AdminStatsUsageFilter {
user_id: Some(auth.user.id.clone()),
provider_name: None,
@@ -872,14 +885,22 @@ pub(super) async fn handle_users_me_usage_active_get(
Err(response) => return response,
};
let ids = parse_users_me_usage_ids(request_context.request_query_string.as_deref());
// When polling for active (pending/streaming) requests without specific ids,
// limit to the last 1 hour to avoid scanning all historical records.
let created_from = if ids.is_none() {
Some(Utc::now().timestamp().saturating_sub(3600) as u64)
} else {
None
};
let items = match state
.list_usage_audits(&UsageAuditListQuery {
created_from_unix_secs: None,
created_from_unix_secs: created_from,
created_until_unix_secs: None,
user_id: Some(auth.user.id.clone()),
provider_name: None,
model: None,
statuses: None,
limit: None,
})
.await
{
@@ -952,6 +973,7 @@ pub(super) async fn handle_users_me_usage_interval_timeline_get(
provider_name: None,
model: None,
statuses: None,
limit: None,
})
.await
{

View File

@@ -218,6 +218,7 @@ pub(super) async fn handle_wallet_today_cost(
provider_name: None,
model: None,
statuses: None,
limit: None,
})
.await
{