Skip to content

Commit e09f638

Browse files
authored
fix(restore): make deployment-ready timeout configurable via env (#47)
2 parents 71fc4d4 + 559d595 commit e09f638

3 files changed

Lines changed: 35 additions & 4 deletions

File tree

src/bin/operator.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use tower_http::trace::TraceLayer;
2020
use tracing::{debug, info, warn};
2121

2222
use postgres_restore_operator::{
23-
context::{Context, DEFAULT_KOPIA_IMAGE},
23+
context::{Context, DEFAULT_DEPLOYMENT_READY_TIMEOUT_SECS, DEFAULT_KOPIA_IMAGE},
2424
controllers,
2525
types::{PostgresPhysicalReplica, PostgresPhysicalRestore},
2626
};
@@ -169,12 +169,28 @@ async fn main() -> anyhow::Result<()> {
169169

170170
annotate_own_pod(&client, &namespace).await;
171171

172+
let deployment_ready_timeout_secs = std::env::var("DEPLOYMENT_READY_TIMEOUT_SECS")
173+
.ok()
174+
.and_then(|v| {
175+
v.parse::<u64>()
176+
.map_err(
177+
|e| warn!(value = v, error = %e, "invalid DEPLOYMENT_READY_TIMEOUT_SECS, using default"),
178+
)
179+
.ok()
180+
})
181+
.unwrap_or(DEFAULT_DEPLOYMENT_READY_TIMEOUT_SECS);
182+
info!(
183+
deployment_ready_timeout_secs,
184+
"deployment readiness timeout configured"
185+
);
186+
172187
let ctx = Arc::new(Context::new(
173188
client.clone(),
174189
max_concurrent_restores,
175190
kopia_image,
176191
use_port_forward,
177192
callback_base_url,
193+
deployment_ready_timeout_secs,
178194
));
179195

180196
// Heartbeat: a background task updates this timestamp every 5s.
@@ -494,6 +510,7 @@ mod tests {
494510
DEFAULT_KOPIA_IMAGE.to_string(),
495511
false,
496512
"http://test.svc:8080".to_string(),
513+
DEFAULT_DEPLOYMENT_READY_TIMEOUT_SECS,
497514
));
498515
let heartbeat = Arc::new(AtomicI64::new(Timestamp::now().as_second()));
499516
let state = ServerState { heartbeat, ctx };

src/context.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use kube::runtime::events::{Recorder, Reporter};
1010
use crate::{controllers::jobs::CallbackStore, metrics::Metrics};
1111

1212
pub const DEFAULT_KOPIA_IMAGE: &str = "kopia/kopia:0.22.3";
13+
pub const DEFAULT_DEPLOYMENT_READY_TIMEOUT_SECS: u64 = 30 * 60;
1314

1415
pub struct Context {
1516
pub client: Client,
@@ -27,6 +28,12 @@ pub struct Context {
2728
/// Base URL the operator is reachable at from within the cluster,
2829
/// e.g. `http://postgres-restore-operator.pgro-system.svc:8080`.
2930
pub callback_base_url: String,
31+
/// Seconds to wait for a restore's postgres Deployment to become Ready
32+
/// after the kopia restore Job completes, before marking the restore
33+
/// Failed. Configurable via the `DEPLOYMENT_READY_TIMEOUT_SECS` env
34+
/// var so it can be raised for replicas with large data dirs (slower
35+
/// WAL replay) without needing a code release.
36+
pub deployment_ready_timeout_secs: u64,
3037
/// Unix timestamp of the last successful entry into a reconcile function.
3138
/// Used by `/livez` to detect a stuck reconciliation loop.
3239
pub last_reconcile: Arc<AtomicI64>,
@@ -39,6 +46,7 @@ impl Context {
3946
kopia_image: String,
4047
use_port_forward: bool,
4148
callback_base_url: String,
49+
deployment_ready_timeout_secs: u64,
4250
) -> Self {
4351
let reporter = Reporter::from("postgres-restore-operator");
4452
let recorder = Recorder::new(client.clone(), reporter);
@@ -55,6 +63,7 @@ impl Context {
5563
snapshot_results: Arc::new(CallbackStore::default()),
5664
schema_migration_results: Arc::new(CallbackStore::default()),
5765
callback_base_url,
66+
deployment_ready_timeout_secs,
5867
last_reconcile: Arc::new(AtomicI64::new(Timestamp::now().as_second())),
5968
}
6069
}

src/controllers/restore.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -766,13 +766,18 @@ async fn reconcile_ready(
766766
return Ok(Action::requeue(Duration::from_secs(5)));
767767
}
768768

769-
// Check for timeout (10 minutes)
769+
// Deployment readiness timeout. Replicas with larger data dirs need
770+
// time for postgres to open the data dir and replay WAL after a
771+
// fresh kopia restore. Default is 30 minutes; tunable per-cluster
772+
// via the `DEPLOYMENT_READY_TIMEOUT_SECS` env var so larger replicas
773+
// can raise it without a code release.
770774
if let Some(created_at) = restore.status.as_ref().and_then(|s| s.restored_at.as_ref()) {
771775
let elapsed = Timestamp::now().duration_since(created_at.0);
772-
if elapsed > SignedDuration::from_secs(10 * 60) {
776+
let timeout_secs = ctx.deployment_ready_timeout_secs;
777+
if elapsed > SignedDuration::from_secs(timeout_secs as i64) {
773778
warn!(
774779
restore = name,
775-
"deployment not ready after 10 minutes, marking as Failed"
780+
timeout_secs, "deployment not ready within configured timeout, marking as Failed"
776781
);
777782
return fail_restore(
778783
ctx,

0 commit comments

Comments
 (0)