use std::time::{Duration, Instant};
pub struct ServiceEndpoint {
pub name: String,
pub url: String,
}
impl ServiceEndpoint {
pub fn qdrant(host: &str, port: u16) -> Self {
Self {
name: format!("Qdrant at {host}:{port}"),
url: format!("http://{host}:{port}/readyz"),
}
}
pub fn elasticsearch(host: &str, port: u16) -> Self {
Self {
name: format!("Elasticsearch at {host}:{port}"),
url: format!("http://{host}:{port}/_cluster/health"),
}
}
}
pub fn wait_for_service(
endpoint: &ServiceEndpoint,
timeout: Duration,
interval: Duration,
) -> Result<(), String> {
let client = reqwest::blocking::Client::builder()
.timeout(Duration::from_secs(5))
.build()
.map_err(|e| format!("Failed to build HTTP client: {e}"))?;
eprintln!("Waiting for {}...", endpoint.name);
let start = Instant::now();
loop {
match client.get(&endpoint.url).send() {
Ok(resp) if resp.status().is_success() => {
eprintln!("{} is ready", endpoint.name);
return Ok(());
}
_ => {}
}
if start.elapsed() >= timeout {
return Err(format!(
"{} did not become ready within {:.0}s",
endpoint.name,
timeout.as_secs_f64()
));
}
std::thread::sleep(interval);
}
}
pub fn wait_for_services(profile: &str) -> Result<(), String> {
let timeout = Duration::from_secs(
std::env::var("TIMEOUT")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(120),
);
let interval = Duration::from_secs(
std::env::var("INTERVAL")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(5),
);
let endpoints: Vec<ServiceEndpoint> = match profile {
"qdrant" => vec![
ServiceEndpoint::qdrant("localhost", 6333),
ServiceEndpoint::qdrant("localhost", 6334),
],
"elastic" => vec![
ServiceEndpoint::elasticsearch("localhost", 9200),
ServiceEndpoint::elasticsearch("localhost", 9201),
],
"mixed" => vec![
ServiceEndpoint::qdrant("localhost", 6333),
ServiceEndpoint::elasticsearch("localhost", 9200),
],
"all" => vec![
ServiceEndpoint::qdrant("localhost", 6333),
ServiceEndpoint::qdrant("localhost", 6335),
ServiceEndpoint::elasticsearch("localhost", 9200),
ServiceEndpoint::elasticsearch("localhost", 9201),
],
_ => {
return Err(format!(
"Unknown profile: {profile}. Use: qdrant, elastic, mixed, all"
))
}
};
for ep in &endpoints {
wait_for_service(ep, timeout, interval)?;
}
eprintln!("All services are ready!");
Ok(())
}