Legg til retry med backoff for Claude API-feil (500/529)

Maskinrommet prøver nå opptil 3 ganger med eksponentiell backoff
(2, 4, 8 sek) ved 500/529-feil fra Anthropic. Etter alle forsøk
vises en vennlig melding i chatten i stedet for rå feilmeldinger.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
vegard 2026-03-17 21:56:54 +00:00
parent d4715831bf
commit 244da69110

View file

@ -155,12 +155,16 @@ Svar KUN med meldingsteksten.
{conversation}--- Svar ---"#
);
// Kall claude CLI direkte
// Kall claude CLI med retry ved API-feil (500/529)
let claude_path = std::env::var("CLAUDE_PATH").unwrap_or_else(|_| "claude".to_string());
let project_dir = std::env::var("PROJECT_DIR").unwrap_or_else(|_| "/home/vegard/synops".to_string());
tracing::info!(prompt_len = prompt.len(), "Kaller claude CLI");
let max_retries = 3u32;
let mut response_text = String::new();
for attempt in 0..=max_retries {
let output = tokio::process::Command::new(&claude_path)
.arg("-p")
.arg(&prompt)
@ -173,16 +177,41 @@ Svar KUN med meldingsteksten.
.await
.map_err(|e| format!("Kunne ikke starte claude: {e}"))?;
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
// Sjekk om dette er en retrybar API-feil (500/529)
let is_api_error = !output.status.success()
&& (stderr.contains("500") || stderr.contains("529")
|| stderr.contains("overloaded") || stderr.contains("Internal Server Error"));
if is_api_error && attempt < max_retries {
let delay = std::time::Duration::from_secs(2u64.pow(attempt + 1)); // 2, 4, 8 sek
tracing::warn!(
attempt = attempt + 1,
delay_secs = delay.as_secs(),
"Claude API-feil, prøver igjen"
);
tokio::time::sleep(delay).await;
continue;
}
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
if is_api_error {
// Alle retries brukt opp — gi vennlig melding i stedet for rå feil
tracing::error!(attempts = max_retries + 1, "Claude API utilgjengelig etter alle forsøk");
response_text = "Beklager, jeg er midlertidig utilgjengelig — Anthropic sitt API svarer ikke akkurat nå. Prøv igjen om litt.".to_string();
break;
}
return Err(format!("claude feilet ({}): {}", output.status, &stderr[..stderr.len().min(500)]));
}
let stdout = String::from_utf8_lossy(&output.stdout);
let response_text = match serde_json::from_str::<serde_json::Value>(&stdout) {
response_text = match serde_json::from_str::<serde_json::Value>(&stdout) {
Ok(json) => json["result"].as_str().unwrap_or("").to_string(),
Err(_) => stdout.trim().to_string(),
};
break;
}
if response_text.is_empty() {
return Err("Tom respons fra claude".to_string());