fix: spawn cert check as independent task, never blocks main request timeout
This commit is contained in:
parent
dbbc9c00cc
commit
68093131fa
|
|
@ -93,18 +93,20 @@ async fn run_check(client: &reqwest::Client, monitor: &Monitor, scheduled_at: Op
|
||||||
let is_https = monitor.url.starts_with("https://");
|
let is_https = monitor.url.starts_with("https://");
|
||||||
let url_clone = monitor.url.clone();
|
let url_clone = monitor.url.clone();
|
||||||
|
|
||||||
// Run the HTTP request and cert check concurrently, both under the same timeout.
|
// Wrap request + body read in a hard timeout.
|
||||||
// This prevents a hanging TCP connect in the cert check from blocking the whole check.
|
// Cert check runs as a background task with a shorter cap so it never blocks
|
||||||
let timed = tokio::time::timeout(timeout, async {
|
// the main check — if the cert TLS connect hangs (e.g. site totally down),
|
||||||
let cert_future = async {
|
// we still report the result from the HTTP side within the configured timeout.
|
||||||
if is_https {
|
let cert_handle = if is_https {
|
||||||
check_cert_expiry(&url_clone).await.ok().flatten()
|
Some(tokio::spawn(tokio::time::timeout(
|
||||||
|
std::time::Duration::from_secs(10),
|
||||||
|
async move { check_cert_expiry(&url_clone).await },
|
||||||
|
)))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let req_future = async {
|
let timed = tokio::time::timeout(timeout, async {
|
||||||
let resp = req.send().await?;
|
let resp = req.send().await?;
|
||||||
let status = resp.status();
|
let status = resp.status();
|
||||||
let headers: HashMap<String, String> = resp.headers().iter()
|
let headers: HashMap<String, String> = resp.headers().iter()
|
||||||
|
|
@ -123,12 +125,21 @@ async fn run_check(client: &reqwest::Client, monitor: &Monitor, scheduled_at: Op
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok::<_, reqwest::Error>((status, headers, body))
|
Ok::<_, reqwest::Error>((status, headers, body))
|
||||||
};
|
|
||||||
|
|
||||||
let (cert_result, req_result) = tokio::join!(cert_future, req_future);
|
|
||||||
req_result.map(|(status, headers, body)| (status, headers, body, cert_result))
|
|
||||||
}).await;
|
}).await;
|
||||||
|
|
||||||
|
// Collect cert result — give it up to 2s after the main request finishes,
|
||||||
|
// then abort. This way a fast site still gets cert info, but a hung cert
|
||||||
|
// check never blocks the ping result.
|
||||||
|
let cert_expiry_days = match cert_handle {
|
||||||
|
Some(handle) => {
|
||||||
|
match tokio::time::timeout(std::time::Duration::from_secs(2), handle).await {
|
||||||
|
Ok(Ok(Ok(Ok(days)))) => days,
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
let latency_ms = start.elapsed().as_millis() as u64;
|
let latency_ms = start.elapsed().as_millis() as u64;
|
||||||
|
|
||||||
// Flatten timeout + reqwest errors into a single result
|
// Flatten timeout + reqwest errors into a single result
|
||||||
|
|
@ -150,7 +161,7 @@ async fn run_check(client: &reqwest::Client, monitor: &Monitor, scheduled_at: Op
|
||||||
cert_expiry_days: None,
|
cert_expiry_days: None,
|
||||||
meta: None,
|
meta: None,
|
||||||
},
|
},
|
||||||
Ok((status_raw, headers, body, cert_expiry_days)) => {
|
Ok((status_raw, headers, body)) => {
|
||||||
let status = status_raw.as_u16();
|
let status = status_raw.as_u16();
|
||||||
|
|
||||||
// Evaluate query if present
|
// Evaluate query if present
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue