From f9d4c093b6036542da66b923b9004b5dc9301b13 Mon Sep 17 00:00:00 2001 From: Leonardo Cecchi Date: Tue, 16 Jun 2026 16:58:11 +0200 Subject: [PATCH] fix: restore WAL from replica source during designated primary promotion During a replica cluster failover, the designated primary could incorrectly attempt to restore WALs from its own object store instead of the replica source, causing recovery to fail. This happened because the previous logic relied on IsReplica() returning true, but that flag can already be false while PostgreSQL is still in recovery and needs WALs from the source cluster. Signed-off-by: Leonardo Cecchi --- internal/cnpgi/common/wal.go | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/internal/cnpgi/common/wal.go b/internal/cnpgi/common/wal.go index 7ccc55d..42f8085 100644 --- a/internal/cnpgi/common/wal.go +++ b/internal/cnpgi/common/wal.go @@ -242,20 +242,13 @@ func (w WALServiceImplementation) Restore( var serverName string var objectStoreKey types.NamespacedName - var promotionToken string - if configuration.Cluster.Spec.ReplicaCluster != nil { - promotionToken = configuration.Cluster.Spec.ReplicaCluster.PromotionToken - } - switch { - case promotionToken != "" && configuration.Cluster.Status.LastPromotionToken != promotionToken: - // This is a replica cluster that is being promoted to a primary cluster - // Recover from the replica source object store - serverName = configuration.ReplicaSourceServerName - objectStoreKey = configuration.GetReplicaSourceBarmanObjectKey() - - case configuration.Cluster.IsReplica() && configuration.Cluster.Status.CurrentPrimary == w.InstanceName: - // Designated primary on replica cluster, using replica source object store + case configuration.Cluster.Status.CurrentPrimary == w.InstanceName && + len(configuration.ReplicaSourceBarmanObjectName) > 0: + // restore_command is only called while PostgreSQL is in recovery, so if this + // instance is the current primary with a replica source configured, it must be + // a designated primary that hasn't completed promotion yet. This covers both + // switchover (promotion token) and failover (no promotion token) cases. serverName = configuration.ReplicaSourceServerName objectStoreKey = configuration.GetReplicaSourceBarmanObjectKey()