From ca95bad62860ad4354cea2f2566491395f46b575 Mon Sep 17 00:00:00 2001 From: Yami Date: Tue, 30 Jun 2026 00:54:06 +0200 Subject: [PATCH] fix(probes): skip probes for mirror and standby pods --- internal/controller/databasecluster_probes.go | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/internal/controller/databasecluster_probes.go b/internal/controller/databasecluster_probes.go index becc103..06ded53 100644 --- a/internal/controller/databasecluster_probes.go +++ b/internal/controller/databasecluster_probes.go @@ -27,18 +27,27 @@ import ( // addDatabaseProbes attaches startup, readiness, and liveness probes // to the database container. // -// The probe is a single pg_isready check against the role's local port. -// Port discovery: +// Probe strategy by role: // -// coordinator, standby → fixed 5432 -// segment → 6000 + ordinal (derived from $HOSTNAME) -// mirror → 7000 + ordinal (derived from $HOSTNAME) +// coordinator, segment → pg_isready against the local port (5432 / 6000). +// These roles accept normal SQL connections, so +// pg_isready returns "accepting connections" once +// postgres is up. +// mirror, standby → NO probes. These roles run postgres in continuous +// recovery mode (replaying WAL from a primary) and +// deliberately do NOT accept normal connections. +// pg_isready returns non-zero against them, which +// triggers restart loops in Kubernetes. Mirror and +// standby health is detected by the operator via +// gp_segment_configuration (status='u', mode='s'), +// so K8s-level probes are both unnecessary and +// actively harmful here. // -// 3-probe layout: +// 3-probe layout for coordinator/segment: // // StartupProbe — generous boot window (~10 min) to absorb gpinitsystem // on coord-0 and the wait-for-coordinator phase on -// segments/mirrors. Once it succeeds, readiness + liveness +// segments. Once it succeeds, readiness + liveness // take over. // ReadinessProbe — tight. Pod only appears in Service endpoints when // postgres truly accepts connections. @@ -48,14 +57,18 @@ import ( // All probes pass cleanly through StatefulSet rollouts and operator restarts // because they read state from the pod itself, not from operator status. func addDatabaseProbes(c *corev1.Container, suffix string, image *keldoniov1alpha1.DatabaseImage) { + // Skip probes for replicas in recovery mode. See doc comment above. + if suffix == "mirror" || suffix == "mirrors" || + suffix == "standby" { + return + } + var portExpr string switch suffix { - case "coordinator", "standby": + case "coordinator": portExpr = "5432" case "segment", "segments": portExpr = "6000" - case "mirror", "mirrors": - portExpr = "7000" default: portExpr = "5432" }