fix: classify official download failures

Distinguish terminal HTTP errors from retryable CDN/network failures, record quarantined resources, and report failed download progress.

Fixes #7
This commit is contained in:
2026-07-14 01:30:12 +08:00
parent 25c2c4d40f
commit 4192d7ee4c
15 changed files with 1034 additions and 195 deletions
@@ -503,6 +503,16 @@ struct DaemonDownloadProgress {
status: Option<String>,
bytes: Option<u64>,
transferred_bytes: Option<u64>,
#[serde(default)]
failure_kind: Option<String>,
#[serde(default)]
failure_http_status: Option<u16>,
#[serde(default)]
failure_retryable: Option<bool>,
#[serde(default)]
failure_attempts: Option<usize>,
#[serde(default)]
quarantined: Option<bool>,
}
#[derive(Debug)]
@@ -1980,6 +1990,31 @@ fn print_list(label: &str, values: &[String], limit: usize) {
fn format_daemon_download_progress(progress: &DaemonDownloadProgress) -> String {
let status = progress.status.as_deref().unwrap_or("running");
if status == "failed" {
return format!(
"{}/{} failed kind={} http={} retryable={} attempts={} quarantined={} {}",
progress.index,
progress.total,
progress.failure_kind.as_deref().unwrap_or("unknown"),
progress
.failure_http_status
.map(|status| status.to_string())
.unwrap_or_else(|| "none".to_string()),
progress
.failure_retryable
.map(|retryable| retryable.to_string())
.unwrap_or_else(|| "unknown".to_string()),
progress
.failure_attempts
.map(|attempts| attempts.to_string())
.unwrap_or_else(|| "0".to_string()),
progress
.quarantined
.map(|quarantined| quarantined.to_string())
.unwrap_or_else(|| "false".to_string()),
progress.url
);
}
format!(
"{}/{} {} {}",
progress.index, progress.total, status, progress.url
@@ -2900,6 +2935,11 @@ fn update_daemon_progress(state_dir: &Path, event: &OfficialUpdateProgress) -> a
status: event.download_status.clone(),
bytes: event.download_bytes,
transferred_bytes: event.download_transferred_bytes,
failure_kind: event.download_failure_kind.clone(),
failure_http_status: event.download_failure_http_status,
failure_retryable: event.download_failure_retryable,
failure_attempts: event.download_failure_attempts,
quarantined: event.download_quarantined,
}),
_ if event.stage != "download" => None,
_ => status.download_progress,
@@ -3354,6 +3394,11 @@ impl RotatingStructuredLogger {
"status": event.download_status.as_deref(),
"bytes": event.download_bytes,
"transferred_bytes": event.download_transferred_bytes,
"failure_kind": event.download_failure_kind.as_deref(),
"failure_http_status": event.download_failure_http_status,
"failure_retryable": event.download_failure_retryable,
"failure_attempts": event.download_failure_attempts,
"quarantined": event.download_quarantined,
})),
});
let mut line = serde_json::to_vec(&payload)?;