perf: optimize proxy streaming and database access
This commit is contained in:
@@ -127,6 +127,7 @@ impl CronScheduler {
|
||||
)
|
||||
.execute(&*db)
|
||||
.await?;
|
||||
crate::proxy::token_router::router::invalidate_route_cache();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,9 @@ struct AvailRow {
|
||||
/// single transaction so a partial failure doesn't leave `token_routes` and
|
||||
/// `route_channels` out of sync.
|
||||
pub async fn rebuild_routes(state: &AppState) -> AppResult<RebuildSummary> {
|
||||
rebuild_routes_inner(&state.db).await
|
||||
let summary = rebuild_routes_inner(&state.db).await?;
|
||||
crate::proxy::token_router::router::invalidate_route_cache();
|
||||
Ok(summary)
|
||||
}
|
||||
|
||||
/// Pool-only entry point. Identical to `rebuild_routes`, just decoupled from
|
||||
|
||||
+102
-5
@@ -160,6 +160,23 @@ async fn insert_asset(
|
||||
.execute(&*state.db)
|
||||
.await?;
|
||||
|
||||
if should_project_workspace_asset(status, &metadata) {
|
||||
if let Err(err) = upsert_workspace_asset_daily(
|
||||
state,
|
||||
None,
|
||||
input.user_id,
|
||||
&input.source,
|
||||
&input.kind,
|
||||
size_bytes,
|
||||
file_path.is_some(),
|
||||
1,
|
||||
)
|
||||
.await
|
||||
{
|
||||
tracing::warn!(%err, "failed to update workspace asset projection");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(StoredWorkspaceAsset {
|
||||
public_id: public_id.to_string(),
|
||||
file_name,
|
||||
@@ -169,6 +186,51 @@ async fn insert_asset(
|
||||
})
|
||||
}
|
||||
|
||||
fn should_project_workspace_asset(status: &str, metadata: &Value) -> bool {
|
||||
status == "completed"
|
||||
&& (metadata.pointer("/workspaceAsset/role").and_then(Value::as_str) == Some("output")
|
||||
|| metadata.pointer("/workflowUi/type").and_then(Value::as_str) == Some("output")
|
||||
|| metadata.get("responseItem").is_some()
|
||||
|| metadata.get("moneyPrinter").is_some()
|
||||
|| metadata.get("digitalHuman").is_some())
|
||||
}
|
||||
|
||||
async fn upsert_workspace_asset_daily(
|
||||
state: &AppState,
|
||||
local_day: Option<&str>,
|
||||
user_id: Option<i64>,
|
||||
source: &str,
|
||||
kind: &str,
|
||||
size_bytes: i64,
|
||||
has_local_file: bool,
|
||||
delta: i64,
|
||||
) -> Result<(), AppError> {
|
||||
let asset_count_delta = delta;
|
||||
let local_file_delta = if has_local_file { delta } else { 0 };
|
||||
let size_delta = size_bytes.max(0) * delta;
|
||||
|
||||
sqlx::query(
|
||||
"INSERT INTO workspace_asset_daily
|
||||
(local_day, user_id, source, kind, asset_count, local_file_count, total_size_bytes, updated_at)
|
||||
VALUES (COALESCE(?, date('now', 'localtime')), ?, ?, ?, ?, ?, ?, datetime('now'))
|
||||
ON CONFLICT(local_day, user_id, source, kind) DO UPDATE SET
|
||||
asset_count = MAX(0, asset_count + excluded.asset_count),
|
||||
local_file_count = MAX(0, local_file_count + excluded.local_file_count),
|
||||
total_size_bytes = MAX(0, total_size_bytes + excluded.total_size_bytes),
|
||||
updated_at = datetime('now')",
|
||||
)
|
||||
.bind(local_day)
|
||||
.bind(user_id.unwrap_or(0))
|
||||
.bind(source)
|
||||
.bind(kind)
|
||||
.bind(asset_count_delta)
|
||||
.bind(local_file_delta)
|
||||
.bind(size_delta)
|
||||
.execute(&*state.db)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn record_remote_asset(
|
||||
state: &AppState,
|
||||
input: WorkspaceAssetInput,
|
||||
@@ -188,11 +250,7 @@ pub async fn record_remote_asset(
|
||||
.await;
|
||||
};
|
||||
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(std::time::Duration::from_secs(60))
|
||||
.build()
|
||||
.unwrap_or_else(|_| reqwest::Client::new());
|
||||
match client.get(url).send().await {
|
||||
match state.http.get(url).send().await {
|
||||
Ok(response) if response.status().is_success() => {
|
||||
let mime_type = response
|
||||
.headers()
|
||||
@@ -307,6 +365,45 @@ pub async fn record_bytes_asset(
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn project_deleted_asset(state: &AppState, public_id: &str) -> Result<(), AppError> {
|
||||
use sqlx::Row;
|
||||
let row = sqlx::query(
|
||||
"SELECT user_id, source, kind, status, metadata, size_bytes, file_path, date(created_at, 'localtime') AS local_day
|
||||
FROM workspace_assets
|
||||
WHERE public_id = ?
|
||||
LIMIT 1",
|
||||
)
|
||||
.bind(public_id)
|
||||
.fetch_optional(&*state.db)
|
||||
.await?;
|
||||
let Some(row) = row else {
|
||||
return Ok(());
|
||||
};
|
||||
let status: String = row.try_get("status").unwrap_or_default();
|
||||
let metadata_raw: String = row.try_get("metadata").unwrap_or_else(|_| "{}".to_string());
|
||||
let metadata = serde_json::from_str::<Value>(&metadata_raw).unwrap_or_else(|_| json!({}));
|
||||
if !should_project_workspace_asset(&status, &metadata) {
|
||||
return Ok(());
|
||||
}
|
||||
let source: String = row.try_get("source").unwrap_or_default();
|
||||
let kind: String = row.try_get("kind").unwrap_or_default();
|
||||
let user_id: Option<i64> = row.try_get("user_id").ok().flatten();
|
||||
let size_bytes: i64 = row.try_get("size_bytes").unwrap_or_default();
|
||||
let file_path: Option<String> = row.try_get("file_path").ok().flatten();
|
||||
let local_day: Option<String> = row.try_get("local_day").ok().flatten();
|
||||
upsert_workspace_asset_daily(
|
||||
state,
|
||||
local_day.as_deref(),
|
||||
user_id,
|
||||
&source,
|
||||
&kind,
|
||||
size_bytes,
|
||||
file_path.as_deref().is_some_and(|value| !value.trim().is_empty()),
|
||||
-1,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn record_image_assets_from_response(
|
||||
state: &AppState,
|
||||
user_id: Option<i64>,
|
||||
|
||||
Reference in New Issue
Block a user