Skip to content

fix: relay standby backups to tier2 without waiting for the last WAL - #281

Open
armru wants to merge 3 commits into
mainfrom
dev/248
Open

armru wants to merge 3 commits into
mainfrom
dev/248

Conversation

@armru

@armru armru commented Sep 15, 2026

Copy link
Copy Markdown
Member

When a backup is taken on a standby, the sidecar runs klio backup run with --wait-for-wals=false, since a standby can't force a WAL switch on the primary and the last segment might take a while to show up. The problem is that CloseBackup on the WAL server was returning early whenever a WAL file was still missing, without enqueueing the post-backup task, on the assumption that the client would call again. A client that isn't waiting never calls again. So the CNPG Backup went green, nothing was logged, and the tier2 relay (plus the consumer-side verification and maintenance) simply never happened.

On a primary this never showed up because pg_backup_stop switches WAL, so the missing segment arrives within seconds and the retry loop picks it up. That's also why the tier2 e2e tests never caught it: the source clusters had a single instance.

The fix adds an enqueue_without_wals flag to CloseBackupRequest. A client that won't retry sets it and the server enqueues the task right away, still reporting the missing WALs (the client logs them now). Without the flag the behaviour is unchanged, so an old sidecar against a new server, or the other way around, keeps working exactly as today on the primary path.

Testing:

  • new unit test for CloseBackup with an embedded NATS server, covering both the standby and the primary case
  • RecoverClusterFromTier2 now uses a two-instance source cluster, so with the default prefer-standby target the backup is taken on the standby. It fails on main (tier2 replication never completes) and passes with this change. It also switches WAL on the primary after the backup, otherwise on an idle cluster the recovery would wait forever for the segment holding the backup end.

Closes #248

Signed-off-by: Armando Ruocco armando.ruocco@enterprisedb.com

@armru
armru requested review from a team and jlong49 as code owners September 15, 2026 14:20
@GabriFedi97
GabriFedi97 force-pushed the dev/248 branch 3 times, most recently from ed45d49 to dbfa6e2 Compare September 17, 2026 07:15
armru and others added 3 commits September 17, 2026 04:41
A backup taken on a standby runs `klio backup run --wait-for-wals=false`,
because a standby cannot force a WAL switch on the primary and its last
segment may take a long time to arrive. The WAL server, however, returned
from CloseBackup without enqueueing the post-backup task whenever a WAL
file was still missing, relying on the client to call again. A client
that does not wait never calls again, so the backup completed with no
error while its tier2 relay, consumer-side verification and maintenance
silently never ran.

CloseBackupRequest gains a `wait_for_wals` flag carrying the client's
intent. The server defers the task only when the client will retry;
otherwise it enqueues the task right away and still reports the missing
WAL files, which the client now logs when it does not wait for them.

The tier2 recovery e2e now uses a two-instance source cluster so the
backup, with the default prefer-standby target, is taken on the standby,
and switches WAL on the primary after the backup so the recovery can
reach the backup end.

Closes #248

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
Rename the new CloseBackupRequest flag to `enqueue_without_wals` and
invert it, so that a request without the flag behaves as before: the
post-backup task is deferred until no WAL file is missing. Only a client
that will not call again, i.e. a backup taken on a standby, opts in.

The Server image is chosen in the Server resource while the sidecar
image comes from the operator, so the two can be on different versions.
With the previous polarity an old sidecar talking to a new server would
have enqueued one task per retry while waiting for WALs on a primary.
With this one neither skew direction changes the primary path.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
The flag documents a client that does not wait for the last WAL to be
archived, whatever the reason. Reword the proto comment, the server-side
comment in CloseBackup and the two test comments accordingly, so a
standby backup reads as one user of the flag rather than its definition.

Signed-off-by: Gabriele Fedi <gabriele.fedi@enterprisedb.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Backups taken on a standby can silently never reach tier2

2 participants