Enables one synchronous standby on ak-pg and pprl-pg (both 2-instance clusters) using CNPG's modern spec.postgresql.synchronous block with dataDurability: preferred. This eliminates the dominant cause of slow switchover: the new primary chasing missing WAL after the old one terminated mid-stream.
What slow today looks like
Today's kubelet-restart on k8s-2 (ak-pg) and k8s-3 (pprl-pg) each triggered a CNPG-managed switchover that took ~5 minutes from probe-failure to client reconnection. From the ak-pg-2 instance-manager logs:
07:57:00 pg_ctl promote -w called
07:59:01 postgres: "received promote request" + "redo done" (+2m)
08:01:03 postgres: "selected new timeline ID: 4" (+2m)
08:02:03 postgres: history file restored from archive
08:02:04 database system ready to accept connections
The two-minute gap from pg_ctl promote to "received promote request" is the standby cycling through wal_retrieve_retry_interval + barman-cloud-wal-restore probes against garage-synology S3 looking for WAL the old primary never archived before it died. Sync replication eliminates this entirely.
preferred keeps fast switchover when the cluster is healthy without sacrificing write availability when a standby fails. The trade-off versus current async config is ~1–5 ms added commit latency on healthy LAN+Ceph — well under noise for authentik and paperless workloads.
What this is NOT
Not touched: im-pg (immich) and gf-pg (grafana). Both are 1-instance; sync replication requires ≥2.
Not changed: any other postgres parameters, resources, or behavior. Just the synchronous: block.
Rollout
On merge, CNPG applies the new config to the live Cluster CRs. Each cluster gets synchronous_standby_names = "ANY 1 (...)" set; postgres reloads config (no restart). Standby starts acking commits within seconds.
Test plan
Merge
kubectl -n authentik get cluster ak-pg -o yaml | yq .spec.postgresql.synchronous shows the new block
## Summary
Enables one synchronous standby on `ak-pg` and `pprl-pg` (both 2-instance clusters) using CNPG's modern `spec.postgresql.synchronous` block with `dataDurability: preferred`. This eliminates the dominant cause of slow switchover: the new primary chasing missing WAL after the old one terminated mid-stream.
## What slow today looks like
Today's kubelet-restart on k8s-2 (ak-pg) and k8s-3 (pprl-pg) each triggered a CNPG-managed switchover that took ~5 minutes from probe-failure to client reconnection. From the ak-pg-2 instance-manager logs:
```
07:57:00 pg_ctl promote -w called
07:59:01 postgres: "received promote request" + "redo done" (+2m)
08:01:03 postgres: "selected new timeline ID: 4" (+2m)
08:02:03 postgres: history file restored from archive
08:02:04 database system ready to accept connections
```
The two-minute gap from `pg_ctl promote` to "received promote request" is the standby cycling through `wal_retrieve_retry_interval` + `barman-cloud-wal-restore` probes against garage-synology S3 looking for WAL the old primary never archived before it died. Sync replication eliminates this entirely.
## Change
```yaml
spec:
postgresql:
parameters:
shared_buffers: "256MB"
max_connections: "400"
synchronous:
method: any
number: 1
dataDurability: preferred
```
| File | Cluster |
|---|---|
| `kubernetes/seed/authentik/cluster.yaml` | ak-pg |
| `kubernetes/seed/paperless/cluster.yaml` | pprl-pg |
## Why `dataDurability: preferred`
| Setting | Standby healthy | Standby down |
|---|---|---|
| `required` | Sync — instant switchover | **Writes block** until standby returns |
| `preferred` | Sync — instant switchover | Falls back to async — writes continue |
`preferred` keeps fast switchover when the cluster is healthy without sacrificing write availability when a standby fails. The trade-off versus current async config is ~1–5 ms added commit latency on healthy LAN+Ceph — well under noise for authentik and paperless workloads.
## What this is NOT
- **Not** touched: `im-pg` (immich) and `gf-pg` (grafana). Both are 1-instance; sync replication requires ≥2.
- **Not** changed: any other postgres parameters, resources, or behavior. Just the `synchronous:` block.
## Rollout
On merge, CNPG applies the new config to the live Cluster CRs. Each cluster gets `synchronous_standby_names = "ANY 1 (...)"` set; postgres reloads config (no restart). Standby starts acking commits within seconds.
## Test plan
- [ ] Merge
- [ ] `kubectl -n authentik get cluster ak-pg -o yaml | yq .spec.postgresql.synchronous` shows the new block
- [ ] `kubectl -n authentik exec ak-pg-2 -c postgres -- psql -t -c "SHOW synchronous_standby_names"` returns `ANY 1 ("ak-pg-1")` (or similar)
- [ ] Repeat for paperless
- [ ] Validate by triggering a switchover (e.g. `kubectl cnpg promote ak-pg ak-pg-1` after merge); time-to-ready should drop from ~5min to <30s
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Today's kubelet-restart-induced switchovers on ak-pg and pprl-pg each
took ~5 minutes from probe-failure to authentik/paperless reconnecting,
dominated by ~4 minutes of postgres-internal promote work. Most of
that time is the new primary chasing missing WAL via barman-cloud (the
old primary terminated mid-stream, queued WAL had to be replayed from
the archive) and the standby waiting through wal_retrieve_retry_interval
cycles before noticing the promote trigger.
With one synchronous standby (`synchronous.number: 1`), the standby is
always at the same LSN as the primary at commit time, so on promote
there is no missing WAL to chase and the standby is immediately ready
to accept connections. CNPG switchovers in this mode complete in single
digits of seconds.
`dataDurability: preferred` (CNPG v1.20+ modern API, replaces the
legacy minSyncReplicas/maxSyncReplicas fields) makes sync best-effort:
the primary stops waiting for the standby if it becomes unavailable,
so a standby outage does not block writes. The trade-off versus async
is ~1-5 ms of added commit latency on healthy LAN+Ceph, which is well
under the noise floor for authentik and paperless workloads.
Single-instance clusters (im-pg, gf-pg) are not touched - sync
replication requires >= 2 instances.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Enables one synchronous standby on
ak-pgandpprl-pg(both 2-instance clusters) using CNPG's modernspec.postgresql.synchronousblock withdataDurability: preferred. This eliminates the dominant cause of slow switchover: the new primary chasing missing WAL after the old one terminated mid-stream.What slow today looks like
Today's kubelet-restart on k8s-2 (ak-pg) and k8s-3 (pprl-pg) each triggered a CNPG-managed switchover that took ~5 minutes from probe-failure to client reconnection. From the ak-pg-2 instance-manager logs:
The two-minute gap from
pg_ctl promoteto "received promote request" is the standby cycling throughwal_retrieve_retry_interval+barman-cloud-wal-restoreprobes against garage-synology S3 looking for WAL the old primary never archived before it died. Sync replication eliminates this entirely.Change
kubernetes/seed/authentik/cluster.yamlkubernetes/seed/paperless/cluster.yamlWhy
dataDurability: preferredrequiredpreferredpreferredkeeps fast switchover when the cluster is healthy without sacrificing write availability when a standby fails. The trade-off versus current async config is ~1–5 ms added commit latency on healthy LAN+Ceph — well under noise for authentik and paperless workloads.What this is NOT
im-pg(immich) andgf-pg(grafana). Both are 1-instance; sync replication requires ≥2.synchronous:block.Rollout
On merge, CNPG applies the new config to the live Cluster CRs. Each cluster gets
synchronous_standby_names = "ANY 1 (...)"set; postgres reloads config (no restart). Standby starts acking commits within seconds.Test plan
kubectl -n authentik get cluster ak-pg -o yaml | yq .spec.postgresql.synchronousshows the new blockkubectl -n authentik exec ak-pg-2 -c postgres -- psql -t -c "SHOW synchronous_standby_names"returnsANY 1 ("ak-pg-1")(or similar)kubectl cnpg promote ak-pg ak-pg-1after merge); time-to-ready should drop from ~5min to <30s🤖 Generated with Claude Code