diff --git a/src/scripts/postgres.rs b/src/scripts/postgres.rs index 50ba0d9..8d94631 100644 --- a/src/scripts/postgres.rs +++ b/src/scripts/postgres.rs @@ -5,7 +5,7 @@ use std::{ path::{Path, PathBuf}, process::Stdio, thread, - time::Duration, + time::{Duration, Instant}, }; use super::docker_compose; @@ -16,6 +16,9 @@ const CUSTOM_MAGIC: &[u8] = b"PGDMP"; const TAR_MAGIC: &[u8] = b"toc.dat"; const GZIP_MAGIC: &[u8] = b"\x1f\x8b"; const CLUSTER_MARKER: &str = "PostgreSQL database cluster dump"; +const READY_TIMEOUT: Duration = Duration::from_secs(60); +const POLL_INTERVAL: Duration = Duration::from_secs(1); + // wide enough for the cluster marker, which sits a few bytes into the file const HEADER_LEN: usize = 512; @@ -191,23 +194,36 @@ fn piped(db: &Database, script: &str, input: &Path) -> Result Result<()> { debug_eprintln!("waiting until pg_isready"); - while !CommandBuilder::docker() - .args("exec") - .arg(&db.container) - .args("pg_isready -U") - .arg(&db.user) - .args("-d") - .arg(&db.name) - .build()? - .stdout(Stdio::null()) - .spawn()? - .wait()? - .success() - { - thread::sleep(Duration::from_secs(1)); - } + let deadline = Instant::now() + READY_TIMEOUT; - Ok(()) + loop { + let ready = CommandBuilder::docker() + .args("exec") + .arg(&db.container) + .args("pg_isready -U") + .arg(&db.user) + .args("-d") + .arg(&db.name) + .build()? + .stdout(Stdio::null()) + .spawn()? + .wait()? + .success(); + + if ready { + return Ok(()); + } + + if Instant::now() >= deadline { + bail!( + "{} did not accept connections within {} seconds", + db.service, + READY_TIMEOUT.as_secs() + ); + } + + thread::sleep(POLL_INTERVAL); + } } fn when_ready(db: &Database, command: CommandBuilder) -> Result<()> {