fix(alphavantage): resolve 404 profile issue by serializing requests and adding rate limit protection

This commit is contained in:
Lv, Qi 2025-11-22 00:12:42 +08:00
parent 0cb31e363e
commit 6c880f51dd

View File

@ -136,26 +136,32 @@ async fn handle_fetch_command_inner(
// Add datatype=json to force JSON response if supported (or at least Python-dict like) // Add datatype=json to force JSON response if supported (or at least Python-dict like)
let params_quote = vec![("symbol", av_symbol.as_str()), ("datatype", "json")]; let params_quote = vec![("symbol", av_symbol.as_str()), ("datatype", "json")];
let overview_task = client.query("COMPANY_OVERVIEW", &params_overview); let overview_json = client.query("COMPANY_OVERVIEW", &params_overview).await?;
let income_task = client.query("INCOME_STATEMENT", &params_income); check_av_response(&overview_json)?;
let balance_task = client.query("BALANCE_SHEET", &params_balance); tokio::time::sleep(std::time::Duration::from_secs(2)).await; // Rate limit protection
let cashflow_task = client.query("CASH_FLOW", &params_cashflow);
let quote_task = client.query("GLOBAL_QUOTE", &params_quote);
let data = match tokio::try_join!( let quote_json = client.query("GLOBAL_QUOTE", &params_quote).await?;
overview_task, check_av_response(&quote_json)?;
income_task, tokio::time::sleep(std::time::Duration::from_secs(2)).await;
balance_task,
cashflow_task, let income_json = client.query("INCOME_STATEMENT", &params_income).await?;
quote_task check_av_response(&income_json)?;
) { tokio::time::sleep(std::time::Duration::from_secs(2)).await;
Ok(data) => data,
Err(e) => { let balance_json = client.query("BALANCE_SHEET", &params_balance).await?;
let error_msg = format!("Failed to fetch data from AlphaVantage: {}", e); check_av_response(&balance_json)?;
error!(error_msg); tokio::time::sleep(std::time::Duration::from_secs(2)).await;
return Err(e);
} let cashflow_json = client.query("CASH_FLOW", &params_cashflow).await?;
}; check_av_response(&cashflow_json)?;
let data = (
overview_json,
income_json,
balance_json,
cashflow_json,
quote_json
);
// Write to Cache // Write to Cache
let payload = serde_json::json!(data); let payload = serde_json::json!(data);
@ -203,6 +209,9 @@ async fn handle_fetch_command_inner(
warn!("Failed to parse CompanyProfile: {}", e); warn!("Failed to parse CompanyProfile: {}", e);
} }
} }
} else {
// If Symbol is missing but check_av_response passed, it might be an empty object {}
warn!("COMPANY_OVERVIEW returned JSON without 'Symbol' field: {:?}", overview_json);
} }
// 2.2 Financials // 2.2 Financials
@ -328,6 +337,16 @@ async fn handle_fetch_command_inner(
Ok(()) Ok(())
} }
fn check_av_response(v: &Value) -> Result<()> {
if let Some(note) = v.get("Note").and_then(|s| s.as_str()) {
return Err(AppError::Internal(format!("AlphaVantage Rate Limit: {}", note)));
}
if let Some(info) = v.get("Information").and_then(|s| s.as_str()) {
return Err(AppError::Internal(format!("AlphaVantage Information: {}", info)));
}
Ok(())
}
async fn update_task_progress(tasks: &TaskStore, request_id: Uuid, percent: u8, details: &str, status: Option<TaskStatus>) { async fn update_task_progress(tasks: &TaskStore, request_id: Uuid, percent: u8, details: &str, status: Option<TaskStatus>) {
if let Some(mut task) = tasks.get_mut(&request_id) { if let Some(mut task) = tasks.get_mut(&request_id) {
task.progress_percent = percent; task.progress_percent = percent;