perf: speed up app loading

This commit is contained in:
boos
2026-06-06 19:21:59 +08:00
parent 9c1e5ae293
commit ef0f91e683
8 changed files with 272 additions and 118 deletions
+87 -22
View File
@@ -29,16 +29,22 @@ pub fn routes() -> Router<AppState> {
)
}
async fn user_picture_log_items(state: &AppState, user_id: i64) -> AppResult<Vec<Value>> {
async fn user_picture_log_items_limited(
state: &AppState,
user_id: i64,
limit: i64,
) -> AppResult<Vec<Value>> {
let tasks: Vec<BackgroundTask> = sqlx::query_as(
"SELECT *
FROM background_tasks
WHERE task_type = ?
AND json_extract(result_json, '$.userId') = ?
ORDER BY created_at DESC, id DESC",
ORDER BY created_at DESC, id DESC
LIMIT ?",
)
.bind("picture-agent-generation")
.bind(user_id)
.bind(limit.clamp(1, 5000))
.fetch_all(&*state.db)
.await?;
@@ -102,7 +108,11 @@ async fn user_picture_log_items(state: &AppState, user_id: i64) -> AppResult<Vec
.collect())
}
async fn user_usage_log_items(state: &AppState, user_id: i64) -> AppResult<Vec<Value>> {
async fn user_usage_log_items_limited(
state: &AppState,
user_id: i64,
limit: i64,
) -> AppResult<Vec<Value>> {
let rows = sqlx::query(
r#"
SELECT
@@ -118,10 +128,11 @@ async fn user_usage_log_items(state: &AppState, user_id: i64) -> AppResult<Vec<V
JOIN downstream_api_keys k ON k.id = l.downstream_key_id
WHERE k.user_id = ?
ORDER BY l.created_at DESC, l.id DESC
LIMIT 5000
LIMIT ?
"#,
)
.bind(user_id)
.bind(limit.clamp(1, 5000))
.fetch_all(&*state.db)
.await?;
@@ -285,6 +296,16 @@ fn sort_user_logs_desc(items: &mut [Value]) {
}
async fn load_user_log_items(state: &AppState, user_id: i64) -> AppResult<Vec<Value>> {
load_user_log_items_limited(state, user_id, 5000, false).await
}
async fn load_user_log_items_limited(
state: &AppState,
user_id: i64,
limit: i64,
truncate_combined: bool,
) -> AppResult<Vec<Value>> {
let limit = limit.clamp(1, 5000);
let mut items: Vec<Value> = sqlx::query_as::<_, crate::routes::stats::ProxyLogRow>(
r#"
SELECT
@@ -308,22 +329,78 @@ async fn load_user_log_items(state: &AppState, user_id: i64) -> AppResult<Vec<Va
LEFT JOIN sites s ON s.id = a.site_id
WHERE k.user_id = ?
ORDER BY l.created_at DESC
LIMIT 5000
LIMIT ?
"#,
)
.bind(user_id)
.bind(limit)
.fetch_all(&*state.db)
.await?
.into_iter()
.map(|row| serde_json::to_value(row).unwrap_or(json!({})))
.collect();
items.extend(user_usage_log_items(state, user_id).await?);
items.extend(user_picture_log_items(state, user_id).await?);
items.extend(user_usage_log_items_limited(state, user_id, limit).await?);
items.extend(user_picture_log_items_limited(state, user_id, limit).await?);
sort_user_logs_desc(&mut items);
if truncate_combined {
items.truncate(limit as usize);
}
Ok(items)
}
async fn load_user_log_summary(state: &AppState, user_id: i64) -> AppResult<(i64, i64, f64)> {
let proxy_summary: (i64, i64, f64) = sqlx::query_as(
r#"
SELECT
COUNT(l.id) AS total,
COALESCE(SUM(CASE WHEN l.status = 'success' THEN 1 ELSE 0 END), 0) AS success_count,
COALESCE(SUM(l.estimated_cost), 0.0) AS total_cost
FROM proxy_logs l
JOIN downstream_api_keys k ON l.downstream_api_key_id = k.id
WHERE k.user_id = ?
"#,
)
.bind(user_id)
.fetch_one(&*state.db)
.await?;
let usage_summary: (i64, f64) = sqlx::query_as(
r#"
SELECT
COUNT(l.id) AS total,
COALESCE(SUM(l.cost), 0.0) AS total_cost
FROM usage_logs l
JOIN downstream_api_keys k ON k.id = l.downstream_key_id
WHERE k.user_id = ?
"#,
)
.bind(user_id)
.fetch_one(&*state.db)
.await?;
let picture_summary: (i64, i64) = sqlx::query_as(
r#"
SELECT
COUNT(*) AS total,
COALESCE(SUM(CASE WHEN status = 'succeeded' THEN 1 ELSE 0 END), 0) AS success_count
FROM background_tasks
WHERE task_type = ?
AND json_extract(result_json, '$.userId') = ?
"#,
)
.bind("picture-agent-generation")
.bind(user_id)
.fetch_one(&*state.db)
.await?;
Ok((
proxy_summary.0 + usage_summary.0 + picture_summary.0,
proxy_summary.1 + usage_summary.0 + picture_summary.1,
proxy_summary.2 + usage_summary.1,
))
}
#[derive(Debug, Deserialize)]
struct UpdateProfilePayload {
username: Option<String>,
@@ -537,13 +614,7 @@ async fn get_user_summary(
headers: HeaderMap,
) -> AppResult<Json<Value>> {
let user_id = current_user_id(&headers, &state)?;
let items = load_user_log_items(&state, user_id).await?;
let total = items.len() as i64;
let success_count = items
.iter()
.filter(|item| user_log_status(item).as_str() == "success")
.count() as i64;
let total_cost = items.iter().map(user_log_cost).sum::<f64>();
let (total, success_count, total_cost) = load_user_log_summary(&state, user_id).await?;
Ok(Json(json!({
"totalRequests": total,
@@ -571,14 +642,8 @@ async fn get_user_dashboard(
.fetch_all(&*state.db)
.await?;
let items = load_user_log_items(&state, user_id).await?;
let total = items.len() as i64;
let success_count = items
.iter()
.filter(|item| user_log_status(item).as_str() == "success")
.count() as i64;
let total_cost = items.iter().map(user_log_cost).sum::<f64>();
let recent_logs = items.into_iter().take(5).collect::<Vec<_>>();
let (total, success_count, total_cost) = load_user_log_summary(&state, user_id).await?;
let recent_logs = load_user_log_items_limited(&state, user_id, 5, true).await?;
Ok(Json(json!({
"user": {