fix: stabilize puzzle vector engine asset generation

This commit is contained in:
2026-06-03 02:40:07 +08:00
parent 67ba40c678
commit 08577b66c5
6 changed files with 215 additions and 28 deletions

View File

@@ -11,6 +11,7 @@ pub fn build_vector_engine_image_http_client(
reqwest::Client::builder()
.timeout(Duration::from_millis(settings.request_timeout_ms.max(1)))
.http1_only()
.pool_max_idle_per_host(0)
.build()
.map_err(|error| PlatformImageError::InvalidConfig {
provider: VECTOR_ENGINE_PROVIDER,
@@ -29,7 +30,14 @@ pub(super) fn map_reqwest_error(
) -> PlatformImageError {
let is_timeout = error.is_timeout();
let is_connect = error.is_connect();
let source = error.source().map(ToString::to_string);
let source_chain_parts = collect_error_source_chain(&error);
let source = source_chain_parts.first().cloned();
let source_chain_depth = source_chain_parts.len();
let source_chain = if source_chain_parts.is_empty() {
None
} else {
Some(source_chain_parts.join(" -> "))
};
let message = format!("{context}{error}");
let audit = build_failure_audit(
request_url,
@@ -40,7 +48,7 @@ pub(super) fn map_reqwest_error(
is_timeout,
is_connect,
message.as_str(),
source.clone(),
source_chain.clone().or_else(|| source.clone()),
None,
Some(latency_ms),
prompt_chars,
@@ -56,6 +64,8 @@ pub(super) fn map_reqwest_error(
body = error.is_body(),
status = error.status().map(|status| status.as_u16()).unwrap_or_default(),
source = %source.clone().unwrap_or_default(),
source_chain = %source_chain.clone().unwrap_or_default(),
source_chain_depth,
message = %message,
elapsed_ms = latency_ms,
prompt_chars,
@@ -72,7 +82,62 @@ pub(super) fn map_reqwest_error(
request: error.is_request(),
body: error.is_body(),
status_code: error.status().map(|status| status.as_u16()),
source,
source: source_chain.or(source),
audit: Some(audit),
}
}
fn collect_error_source_chain(error: &(dyn Error + 'static)) -> Vec<String> {
let mut chain = Vec::new();
let mut next = error.source();
while let Some(source) = next {
chain.push(source.to_string());
next = source.source();
}
chain
}
#[cfg(test)]
mod tests {
use super::*;
use std::fmt;
#[derive(Debug)]
struct TestError {
message: &'static str,
source: Option<Box<TestError>>,
}
impl fmt::Display for TestError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.message)
}
}
impl Error for TestError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.source
.as_deref()
.map(|source| source as &(dyn Error + 'static))
}
}
#[test]
fn collect_error_source_chain_keeps_nested_causes() {
let error = TestError {
message: "top",
source: Some(Box::new(TestError {
message: "middle",
source: Some(Box::new(TestError {
message: "bottom",
source: None,
})),
})),
};
assert_eq!(
collect_error_source_chain(&error),
vec!["middle".to_string(), "bottom".to_string()]
);
}
}