From 20fa43752ce023ef6cdf513f801e107d55fd9e66 Mon Sep 17 00:00:00 2001 From: souravbiswassanto Date: Sat, 19 Sep 2026 07:53:20 +0600 Subject: [PATCH] Never emit an empty synchronous_standby_names list The role scripts build synchronous_standby_names from $REPLICAS, skipping the pod's own index. At one replica that list is empty, and the emitted value becomes 'FIRST 2 ()' -- with the mode and quorum still coming from SYNC_REPLICATION_MODE/NUM_SYNC_REPLICAS, which describe the eventual topology rather than the current one. Postgres does not read an empty list as "no synchronous standbys". It is a parse error: LOG: invalid value for parameter "synchronous_standby_names": "FIRST 2 ()" DETAIL: syntax error at or near ")" FATAL: configuration file "/var/pv/data/postgresql.conf" contains errors so the server never starts. scripts/run.sh then re-runs the role script on its one-second loop and start.sh prepends another block each pass, so the file also accumulates duplicate entries while the pod sits not-ready. This is reachable today: a PITR restore with replicationStrategy sync or fscopy -- the default for postgres -- collapses the CR to a single replica while leaving streamingMode Synchronous, so any synchronous cluster with replicas > 1 fails to come back from a restore. Fall back to an empty string when the list is empty. Postgres accepts synchronous_standby_names = '' and treats every synchronous_commit level as local, so commits wait for local flush only: no error and no hang. The next reconcile rewrites the file with a real list once the peers exist. Verified against postgres 16.15: 'FIRST 2 ()' reproduces the error above, '' and 'FIRST 2 ("a","b")' both start. Applied to all 40 emitters (majors 9-18 x primary/start, standby/run, standby/warm_stanby, standby/ha_backup_job); the majors are independent copies, so each needs the guard. No behaviour change when the list is non-empty. Co-Authored-By: Claude Opus 5 (1M context) Signed-off-by: souravbiswassanto --- role_scripts/10/primary/start.sh | 9 ++++++++- role_scripts/10/standby/ha_backup_job.sh | 9 ++++++++- role_scripts/10/standby/run.sh | 9 ++++++++- role_scripts/10/standby/warm_stanby.sh | 9 ++++++++- role_scripts/11/primary/start.sh | 9 ++++++++- role_scripts/11/standby/ha_backup_job.sh | 9 ++++++++- role_scripts/11/standby/run.sh | 9 ++++++++- role_scripts/11/standby/warm_stanby.sh | 9 ++++++++- role_scripts/12/primary/start.sh | 9 ++++++++- role_scripts/12/standby/ha_backup_job.sh | 9 ++++++++- role_scripts/12/standby/run.sh | 9 ++++++++- role_scripts/12/standby/warm_stanby.sh | 9 ++++++++- role_scripts/13/primary/start.sh | 9 ++++++++- role_scripts/13/standby/ha_backup_job.sh | 9 ++++++++- role_scripts/13/standby/run.sh | 9 ++++++++- role_scripts/13/standby/warm_stanby.sh | 9 ++++++++- role_scripts/14/primary/start.sh | 9 ++++++++- role_scripts/14/standby/ha_backup_job.sh | 9 ++++++++- role_scripts/14/standby/run.sh | 9 ++++++++- role_scripts/14/standby/warm_stanby.sh | 9 ++++++++- role_scripts/15/primary/start.sh | 9 ++++++++- role_scripts/15/standby/ha_backup_job.sh | 9 ++++++++- role_scripts/15/standby/run.sh | 9 ++++++++- role_scripts/15/standby/warm_stanby.sh | 9 ++++++++- role_scripts/16/primary/start.sh | 9 ++++++++- role_scripts/16/standby/ha_backup_job.sh | 9 ++++++++- role_scripts/16/standby/run.sh | 9 ++++++++- role_scripts/16/standby/warm_stanby.sh | 9 ++++++++- role_scripts/17/primary/start.sh | 9 ++++++++- role_scripts/17/standby/ha_backup_job.sh | 9 ++++++++- role_scripts/17/standby/run.sh | 9 ++++++++- role_scripts/17/standby/warm_stanby.sh | 9 ++++++++- role_scripts/18/primary/start.sh | 9 ++++++++- role_scripts/18/standby/ha_backup_job.sh | 9 ++++++++- role_scripts/18/standby/run.sh | 9 ++++++++- role_scripts/18/standby/warm_stanby.sh | 9 ++++++++- role_scripts/9/primary/start.sh | 9 ++++++++- role_scripts/9/standby/ha_backup_job.sh | 9 ++++++++- role_scripts/9/standby/run.sh | 9 ++++++++- role_scripts/9/standby/warm_stanby.sh | 9 ++++++++- 40 files changed, 320 insertions(+), 40 deletions(-) diff --git a/role_scripts/10/primary/start.sh b/role_scripts/10/primary/start.sh index a98323b..ba14e81 100755 --- a/role_scripts/10/primary/start.sh +++ b/role_scripts/10/primary/start.sh @@ -369,7 +369,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi # ref: https://superuser.com/a/246841/985093 cat /tmp/postgresql.conf $PGDATA/postgresql.conf >"/tmp/postgresql.conf.tmp" && mv "/tmp/postgresql.conf.tmp" "$PGDATA/postgresql.conf" diff --git a/role_scripts/10/standby/ha_backup_job.sh b/role_scripts/10/standby/ha_backup_job.sh index b6ee739..77dcf29 100755 --- a/role_scripts/10/standby/ha_backup_job.sh +++ b/role_scripts/10/standby/ha_backup_job.sh @@ -139,7 +139,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then echo "ssl = on" >>/tmp/postgresql.conf diff --git a/role_scripts/10/standby/run.sh b/role_scripts/10/standby/run.sh index 0320ae1..7974f11 100755 --- a/role_scripts/10/standby/run.sh +++ b/role_scripts/10/standby/run.sh @@ -203,7 +203,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then echo "ssl = on" >>/tmp/postgresql.conf diff --git a/role_scripts/10/standby/warm_stanby.sh b/role_scripts/10/standby/warm_stanby.sh index 70d6834..4c0c9ad 100755 --- a/role_scripts/10/standby/warm_stanby.sh +++ b/role_scripts/10/standby/warm_stanby.sh @@ -77,7 +77,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then echo "ssl = on" >>/tmp/postgresql.conf diff --git a/role_scripts/11/primary/start.sh b/role_scripts/11/primary/start.sh index f83706d..14bb1b2 100755 --- a/role_scripts/11/primary/start.sh +++ b/role_scripts/11/primary/start.sh @@ -432,7 +432,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi # ref: https://superuser.com/a/246841/985093 cat /tmp/postgresql.conf $PGDATA/postgresql.conf >"/tmp/postgresql.conf.tmp" && mv "/tmp/postgresql.conf.tmp" "$PGDATA/postgresql.conf" diff --git a/role_scripts/11/standby/ha_backup_job.sh b/role_scripts/11/standby/ha_backup_job.sh index 15df5dc..6c5b256 100755 --- a/role_scripts/11/standby/ha_backup_job.sh +++ b/role_scripts/11/standby/ha_backup_job.sh @@ -138,7 +138,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/11/standby/run.sh b/role_scripts/11/standby/run.sh index 0fb80c2..821dd23 100755 --- a/role_scripts/11/standby/run.sh +++ b/role_scripts/11/standby/run.sh @@ -207,7 +207,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then echo "ssl = on" >>/tmp/postgresql.conf diff --git a/role_scripts/11/standby/warm_stanby.sh b/role_scripts/11/standby/warm_stanby.sh index c8e1c58..2aaa507 100755 --- a/role_scripts/11/standby/warm_stanby.sh +++ b/role_scripts/11/standby/warm_stanby.sh @@ -77,7 +77,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/12/primary/start.sh b/role_scripts/12/primary/start.sh index 085572b..99e5913 100755 --- a/role_scripts/12/primary/start.sh +++ b/role_scripts/12/primary/start.sh @@ -452,7 +452,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi # ref: https://superuser.com/a/246841/985093 diff --git a/role_scripts/12/standby/ha_backup_job.sh b/role_scripts/12/standby/ha_backup_job.sh index d79e8d5..163f588 100755 --- a/role_scripts/12/standby/ha_backup_job.sh +++ b/role_scripts/12/standby/ha_backup_job.sh @@ -140,7 +140,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/12/standby/run.sh b/role_scripts/12/standby/run.sh index 85cc2cb..2364562 100755 --- a/role_scripts/12/standby/run.sh +++ b/role_scripts/12/standby/run.sh @@ -205,7 +205,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then echo "ssl = on" >>/tmp/postgresql.conf diff --git a/role_scripts/12/standby/warm_stanby.sh b/role_scripts/12/standby/warm_stanby.sh index d491780..4b6e0c9 100755 --- a/role_scripts/12/standby/warm_stanby.sh +++ b/role_scripts/12/standby/warm_stanby.sh @@ -86,7 +86,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then echo "ssl = on" >>/tmp/postgresql.conf diff --git a/role_scripts/13/primary/start.sh b/role_scripts/13/primary/start.sh index 3cadcce..387d814 100755 --- a/role_scripts/13/primary/start.sh +++ b/role_scripts/13/primary/start.sh @@ -482,7 +482,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi # ref: https://superuser.com/a/246841/985093 diff --git a/role_scripts/13/standby/ha_backup_job.sh b/role_scripts/13/standby/ha_backup_job.sh index ee961bf..89dca66 100755 --- a/role_scripts/13/standby/ha_backup_job.sh +++ b/role_scripts/13/standby/ha_backup_job.sh @@ -140,7 +140,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then echo "ssl = on" >>/tmp/postgresql.conf diff --git a/role_scripts/13/standby/run.sh b/role_scripts/13/standby/run.sh index 7eee1d4..b3bd056 100755 --- a/role_scripts/13/standby/run.sh +++ b/role_scripts/13/standby/run.sh @@ -209,7 +209,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/13/standby/warm_stanby.sh b/role_scripts/13/standby/warm_stanby.sh index b39e1e8..c486898 100755 --- a/role_scripts/13/standby/warm_stanby.sh +++ b/role_scripts/13/standby/warm_stanby.sh @@ -80,7 +80,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/14/primary/start.sh b/role_scripts/14/primary/start.sh index 6015005..b61b096 100755 --- a/role_scripts/14/primary/start.sh +++ b/role_scripts/14/primary/start.sh @@ -487,7 +487,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi # ref: https://superuser.com/a/246841/985093 diff --git a/role_scripts/14/standby/ha_backup_job.sh b/role_scripts/14/standby/ha_backup_job.sh index 444f001..17f2788 100755 --- a/role_scripts/14/standby/ha_backup_job.sh +++ b/role_scripts/14/standby/ha_backup_job.sh @@ -140,7 +140,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then echo "ssl = on" >>/tmp/postgresql.conf diff --git a/role_scripts/14/standby/run.sh b/role_scripts/14/standby/run.sh index 7db01e1..b6884a7 100755 --- a/role_scripts/14/standby/run.sh +++ b/role_scripts/14/standby/run.sh @@ -209,7 +209,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/14/standby/warm_stanby.sh b/role_scripts/14/standby/warm_stanby.sh index 928ec3d..c935f6e 100755 --- a/role_scripts/14/standby/warm_stanby.sh +++ b/role_scripts/14/standby/warm_stanby.sh @@ -80,7 +80,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/15/primary/start.sh b/role_scripts/15/primary/start.sh index 8896043..592d711 100755 --- a/role_scripts/15/primary/start.sh +++ b/role_scripts/15/primary/start.sh @@ -490,7 +490,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi # ref: https://superuser.com/a/246841/985093 diff --git a/role_scripts/15/standby/ha_backup_job.sh b/role_scripts/15/standby/ha_backup_job.sh index ff53d0c..d546b8e 100755 --- a/role_scripts/15/standby/ha_backup_job.sh +++ b/role_scripts/15/standby/ha_backup_job.sh @@ -142,7 +142,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then echo "ssl = on" >>/tmp/postgresql.conf diff --git a/role_scripts/15/standby/run.sh b/role_scripts/15/standby/run.sh index 57c21cc..c780d80 100755 --- a/role_scripts/15/standby/run.sh +++ b/role_scripts/15/standby/run.sh @@ -208,7 +208,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/15/standby/warm_stanby.sh b/role_scripts/15/standby/warm_stanby.sh index efecb83..4e3a5b6 100755 --- a/role_scripts/15/standby/warm_stanby.sh +++ b/role_scripts/15/standby/warm_stanby.sh @@ -81,7 +81,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/16/primary/start.sh b/role_scripts/16/primary/start.sh index 9ecc8d9..c5012c5 100755 --- a/role_scripts/16/primary/start.sh +++ b/role_scripts/16/primary/start.sh @@ -468,7 +468,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi # ref: https://superuser.com/a/246841/985093 diff --git a/role_scripts/16/standby/ha_backup_job.sh b/role_scripts/16/standby/ha_backup_job.sh index c654fcf..98091c5 100755 --- a/role_scripts/16/standby/ha_backup_job.sh +++ b/role_scripts/16/standby/ha_backup_job.sh @@ -142,7 +142,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then echo "ssl = on" >>/tmp/postgresql.conf diff --git a/role_scripts/16/standby/run.sh b/role_scripts/16/standby/run.sh index 63abf86..b5301cd 100755 --- a/role_scripts/16/standby/run.sh +++ b/role_scripts/16/standby/run.sh @@ -209,7 +209,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/16/standby/warm_stanby.sh b/role_scripts/16/standby/warm_stanby.sh index 75a59ea..18c76a2 100755 --- a/role_scripts/16/standby/warm_stanby.sh +++ b/role_scripts/16/standby/warm_stanby.sh @@ -81,7 +81,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/17/primary/start.sh b/role_scripts/17/primary/start.sh index 783406a..6c8bedb 100755 --- a/role_scripts/17/primary/start.sh +++ b/role_scripts/17/primary/start.sh @@ -478,7 +478,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi # ref: https://superuser.com/a/246841/985093 diff --git a/role_scripts/17/standby/ha_backup_job.sh b/role_scripts/17/standby/ha_backup_job.sh index c654fcf..98091c5 100755 --- a/role_scripts/17/standby/ha_backup_job.sh +++ b/role_scripts/17/standby/ha_backup_job.sh @@ -142,7 +142,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then echo "ssl = on" >>/tmp/postgresql.conf diff --git a/role_scripts/17/standby/run.sh b/role_scripts/17/standby/run.sh index 8e518e4..60a3cac 100755 --- a/role_scripts/17/standby/run.sh +++ b/role_scripts/17/standby/run.sh @@ -209,7 +209,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/17/standby/warm_stanby.sh b/role_scripts/17/standby/warm_stanby.sh index 57e6e88..3352733 100755 --- a/role_scripts/17/standby/warm_stanby.sh +++ b/role_scripts/17/standby/warm_stanby.sh @@ -85,7 +85,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/18/primary/start.sh b/role_scripts/18/primary/start.sh index ab734d6..e3fb1c5 100755 --- a/role_scripts/18/primary/start.sh +++ b/role_scripts/18/primary/start.sh @@ -471,7 +471,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi # ref: https://superuser.com/a/246841/985093 diff --git a/role_scripts/18/standby/ha_backup_job.sh b/role_scripts/18/standby/ha_backup_job.sh index c654fcf..98091c5 100755 --- a/role_scripts/18/standby/ha_backup_job.sh +++ b/role_scripts/18/standby/ha_backup_job.sh @@ -142,7 +142,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then echo "ssl = on" >>/tmp/postgresql.conf diff --git a/role_scripts/18/standby/run.sh b/role_scripts/18/standby/run.sh index 8e518e4..60a3cac 100755 --- a/role_scripts/18/standby/run.sh +++ b/role_scripts/18/standby/run.sh @@ -209,7 +209,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/18/standby/warm_stanby.sh b/role_scripts/18/standby/warm_stanby.sh index 57e6e88..3352733 100755 --- a/role_scripts/18/standby/warm_stanby.sh +++ b/role_scripts/18/standby/warm_stanby.sh @@ -85,7 +85,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/9/primary/start.sh b/role_scripts/9/primary/start.sh index 1d98613..0e2eaa9 100755 --- a/role_scripts/9/primary/start.sh +++ b/role_scripts/9/primary/start.sh @@ -364,7 +364,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi # ref: https://superuser.com/a/246841/985093 diff --git a/role_scripts/9/standby/ha_backup_job.sh b/role_scripts/9/standby/ha_backup_job.sh index 6b2830c..106f101 100755 --- a/role_scripts/9/standby/ha_backup_job.sh +++ b/role_scripts/9/standby/ha_backup_job.sh @@ -139,7 +139,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/9/standby/run.sh b/role_scripts/9/standby/run.sh index fca2cd9..cc67f79 100755 --- a/role_scripts/9/standby/run.sh +++ b/role_scripts/9/standby/run.sh @@ -199,7 +199,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then diff --git a/role_scripts/9/standby/warm_stanby.sh b/role_scripts/9/standby/warm_stanby.sh index 779897a..4463a9b 100755 --- a/role_scripts/9/standby/warm_stanby.sh +++ b/role_scripts/9/standby/warm_stanby.sh @@ -78,7 +78,14 @@ if [[ "$STREAMING" == "synchronous" ]]; then done names=${names%,} fi - echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + # An empty list is a syntax error, not "no sync standbys" -- postgres refuses to start on + # 'FIRST 2 ()'. $names is empty whenever this pod is the only member it can see, e.g. a + # PITR restore at one replica. Empty means "wait for local flush only", so this is safe. + if [[ -z "${names:-}" ]]; then + echo "synchronous_standby_names = ''" >>/tmp/postgresql.conf + else + echo "synchronous_standby_names = '${SYNC_REPLICATION_MODE:-ANY} ${NUM_SYNC_REPLICAS:-1} ("$names")'" >>/tmp/postgresql.conf + fi fi if [[ "${SSL:-0}" == "ON" ]]; then