fix(instance-manager): promote a replica without waiting for WAL receivers to stop - #11367
leonardoce wants to merge 9 commits into
Conversation
… failover When a failover is in progress and the old primary's PostgreSQL is unresponsive, skip the checkpoint and fast-shutdown attempts and shut it down immediately instead, so demoting the old primary doesn't stall waiting on timeouts and the failover can complete without delay. Signed-off-by: Leonardo Cecchi <[email protected]>
tryTakeOver read the lease with the caller's un-deadlined context, so a Get against an unreachable API server could block indefinitely instead of retrying at RetryPeriod cadence. That silence starves the lease watchdog's heartbeat, which can fence a primary that is still correctly retrying and has not actually stepped down. Wrap the call in a RetryPeriod-bounded context, mirroring the same pattern already used for the post-renewal lease check. Closes cloudnative-pg#11349 Signed-off-by: Leonardo Cecchi <[email protected]>
…ease Primary self-fencing on network isolation used to live in the liveness probe: on API-server unreachability it pinged every peer's failsafe endpoint, and a failed probe caused Kubelet to restart the pod roughly three probe periods (~30s) after a partition started. The primary lease now gives a faster, more precise signal for the same condition. When the primary fails to renew its lease, it runs the same peer-reachability check itself and, if it should step down, requests a fast PostgreSQL shutdown directly rather than waiting on Kubelet. The check runs as soon as renewal fails (not after waiting out the remaining lease TTL): the RenewDeadline-to-LeaseDuration margin is the time budget for the check-and-shutdown sequence to complete before a replica becomes eligible to promote, not idle slack to wait through. The step-down condition is no longer just peer unreachability: the /failsafe entrypoint now reports the responding instance's view of the cluster's target primary (via a new internal/management/failsafe wire package shared by both sides), so a primary that can still reach every peer but learns from one of them that someone else is now the target primary steps down too. This closes a gap the reachability check alone couldn't see: a peer being reachable doesn't mean it hasn't already been promoted. The liveness probe's isolation logic is removed now that the lease handles it; IsHealthy always reports OK. Signed-off-by: Leonardo Cecchi <[email protected]>
The liveness probe used to always report healthy, so a Pod could never be restarted when it truly got stuck. It now fails, so the kubelet can kill and recreate the Pod, in two cases the primary lease and fencing logic can't recover from on their own: - the primary-lease loop stops attempting to renew or take over the lease altogether (e.g. a deadlock), as opposed to merely failing to renew, which is an expected condition handled separately by the lease/failsafe step-down check; - PostgreSQL was asked to shut down immediately (e.g. because this primary had to step down) but didn't honor it within a new configurable `.spec.immediateShutdownTimeout` (default 30s). Signed-off-by: Leonardo Cecchi <[email protected]>
|
❗ By default, the pull request is configured to backport to all release branches.
|
|
/test |
|
@leonardoce, here's the link to the E2E on CNPG workflow run: https://github.com/cloudnative-pg/cloudnative-pg/actions/runs/32732041476 |
|
This is what happened:
So the primary lease worked correctly, but unfortunately the operator decided which replica to promote too early, without re-checking it before the promotion actually happens. Claude was used to help wording the timeline. |
While a failover was pending (target primary set to the internal "pending" marker), the reconciliation loop kept short-circuiting with a 1-second requeue instead of continuing to check whether the failover could complete, and the status update logic would mistake the marker for a missing pod and reset the target primary back to the unhealthy one. Both effects could leave a failover stuck indefinitely or silently undone. The reconciler now recognizes the pending marker and lets the failover proceed to completion. Signed-off-by: Leonardo Cecchi <[email protected]>
…ivers to stop The primary lease now guarantees only one instance can act as primary at a time, so failovers and switchovers no longer need to stall until every WAL receiver in the cluster reports itself down before a new primary is chosen and promoted. This removes a source of delay and stuck-waiting states during failover. Signed-off-by: Leonardo Cecchi <[email protected]>
The controller used to snapshot replica LSNs and immediately elect a new primary in the same reconcile pass as marking the failover pending, even though the old primary could still be alive and streaming for a few more seconds. That window let the LSN snapshot go stale before the elected replica actually promoted, leaving a sibling replica to fork onto a diverged timeline with no automatic repair. Splits "mark pending" and "elect" into two separate reconcile passes, deferring election until the primary lease is confirmed released or expired, so the LSN snapshot used for the election is taken as close as possible to the actual promotion. Signed-off-by: Leonardo Cecchi <[email protected]>
…former primary When an unreachable former primary has no running postmaster, requesting a shutdown has nothing to act on it and can block forever on the unbuffered command channel. Skip the request in that case, and export IsStatusRunning so the controller can check it. Signed-off-by: Leonardo Cecchi <[email protected]>
f1ad3f1 to
57f3b1d
Compare
|
/test |
|
@leonardoce, here's the link to the E2E on CNPG workflow run: https://github.com/cloudnative-pg/cloudnative-pg/actions/runs/32855976902 |
It looks like the tests time budget is not enough to observe a failover. That's even more important now given that, in these conditions, we need to wait for the lease to expire. |
Signed-off-by: Leonardo Cecchi <[email protected]>
|
/test |
|
@leonardoce, here's the link to the E2E on CNPG workflow run: https://github.com/cloudnative-pg/cloudnative-pg/actions/runs/32943483652 |
|
@leonardoce could this be related to #11114? |
The primary lease now guarantees only one instance can act as primary
at a time, so failovers and switchovers no longer need to stall until
every WAL receiver in the cluster reports itself down before a new
primary is chosen and promoted. This removes a source of delay and
stuck-waiting states during failover.