diff --git a/init_scripts/run.sh b/init_scripts/run.sh index 20f9e1d..503d541 100755 --- a/init_scripts/run.sh +++ b/init_scripts/run.sh @@ -11,8 +11,9 @@ export remote_replica=${REMOTE_REPLICA:-false} export source_ssl=${SOURCE_SSL:-false} if [[ $remote_replica == "true" ]]; then - mkdir -p /run_scripts/role + mkdir -p /run_scripts/role /role_scripts/standby cp -r /tmp/role_scripts/$MAJOR_PG_VERSION/standby/* /run_scripts/role/ + cp -r /tmp/role_scripts/$MAJOR_PG_VERSION/standby/* /role_scripts/standby/ elif [[ $STANDALONE == "true" ]]; then mkdir -p /run_scripts/role cp -r /tmp/role_scripts/$MAJOR_PG_VERSION/primary/* /run_scripts/role/ diff --git a/role_scripts/13/primary/start.sh b/role_scripts/13/primary/start.sh index c4ab448..0675b8d 100755 --- a/role_scripts/13/primary/start.sh +++ b/role_scripts/13/primary/start.sh @@ -91,6 +91,26 @@ export POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} psql=(psql -v ON_ERROR_STOP=1) +# If standby.signal is present, postgres started in recovery above (this node was a standby being +# promoted). Promote it NOW to fork a NEW timeline BEFORE any write below. This is essential for the +# remote-replica -> standalone-HA transition: without promoting from recovery the node comes up on +# the SAME timeline as its former source cluster, which on failback forces a full pg_basebackup +# instead of pg_rewind. Promotion ends recovery, increments the timeline, and removes standby.signal. +# A normal primary start (no standby.signal) skips this block, so fresh bootstrap and the live-standby +# fast-failover path (which promotes via the coordinator, not start.sh) are unaffected. +if [[ -f "/var/pv/data/standby.signal" ]]; then + echo "standby.signal present -> promoting to fork a new timeline before writes" + pg_ctl -D "$PGDATA" promote || true + for _ in $(seq 1 120); do + state=$(pg_controldata "$PGDATA" 2>/dev/null | grep "Database cluster state" | sed 's/.*:[[:space:]]*//') + if [[ "$state" == "in production" ]]; then + echo "promotion complete; node is now primary on a new timeline" + break + fi + sleep 1 + done +fi + # create database with specified name if [ "$POSTGRES_DB" != "postgres" ]; then "${psql[@]}" --username postgres <<-EOSQL diff --git a/role_scripts/14/primary/start.sh b/role_scripts/14/primary/start.sh index cf42d90..2202449 100755 --- a/role_scripts/14/primary/start.sh +++ b/role_scripts/14/primary/start.sh @@ -97,6 +97,26 @@ export POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} psql=(psql -v ON_ERROR_STOP=1) +# If standby.signal is present, postgres started in recovery above (this node was a standby being +# promoted). Promote it NOW to fork a NEW timeline BEFORE any write below. This is essential for the +# remote-replica -> standalone-HA transition: without promoting from recovery the node comes up on +# the SAME timeline as its former source cluster, which on failback forces a full pg_basebackup +# instead of pg_rewind. Promotion ends recovery, increments the timeline, and removes standby.signal. +# A normal primary start (no standby.signal) skips this block, so fresh bootstrap and the live-standby +# fast-failover path (which promotes via the coordinator, not start.sh) are unaffected. +if [[ -f "/var/pv/data/standby.signal" ]]; then + echo "standby.signal present -> promoting to fork a new timeline before writes" + pg_ctl -D "$PGDATA" promote || true + for _ in $(seq 1 120); do + state=$(pg_controldata "$PGDATA" 2>/dev/null | grep "Database cluster state" | sed 's/.*:[[:space:]]*//') + if [[ "$state" == "in production" ]]; then + echo "promotion complete; node is now primary on a new timeline" + break + fi + sleep 1 + done +fi + # create database with specified name if [ "$POSTGRES_DB" != "postgres" ]; then "${psql[@]}" --username postgres <<-EOSQL diff --git a/role_scripts/15/primary/start.sh b/role_scripts/15/primary/start.sh index c628a37..6bc863b 100755 --- a/role_scripts/15/primary/start.sh +++ b/role_scripts/15/primary/start.sh @@ -95,6 +95,26 @@ export POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} psql=(psql -v ON_ERROR_STOP=1) +# If standby.signal is present, postgres started in recovery above (this node was a standby being +# promoted). Promote it NOW to fork a NEW timeline BEFORE any write below. This is essential for the +# remote-replica -> standalone-HA transition: without promoting from recovery the node comes up on +# the SAME timeline as its former source cluster, which on failback forces a full pg_basebackup +# instead of pg_rewind. Promotion ends recovery, increments the timeline, and removes standby.signal. +# A normal primary start (no standby.signal) skips this block, so fresh bootstrap and the live-standby +# fast-failover path (which promotes via the coordinator, not start.sh) are unaffected. +if [[ -f "/var/pv/data/standby.signal" ]]; then + echo "standby.signal present -> promoting to fork a new timeline before writes" + pg_ctl -D "$PGDATA" promote || true + for _ in $(seq 1 120); do + state=$(pg_controldata "$PGDATA" 2>/dev/null | grep "Database cluster state" | sed 's/.*:[[:space:]]*//') + if [[ "$state" == "in production" ]]; then + echo "promotion complete; node is now primary on a new timeline" + break + fi + sleep 1 + done +fi + # create database with specified name if [ "$POSTGRES_DB" != "postgres" ]; then "${psql[@]}" --username postgres <<-EOSQL diff --git a/role_scripts/16/primary/start.sh b/role_scripts/16/primary/start.sh index 0d1c333..a063073 100755 --- a/role_scripts/16/primary/start.sh +++ b/role_scripts/16/primary/start.sh @@ -94,6 +94,26 @@ export POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} psql=(psql -v ON_ERROR_STOP=1) +# If standby.signal is present, postgres started in recovery above (this node was a standby being +# promoted). Promote it NOW to fork a NEW timeline BEFORE any write below. This is essential for the +# remote-replica -> standalone-HA transition: without promoting from recovery the node comes up on +# the SAME timeline as its former source cluster, which on failback forces a full pg_basebackup +# instead of pg_rewind. Promotion ends recovery, increments the timeline, and removes standby.signal. +# A normal primary start (no standby.signal) skips this block, so fresh bootstrap and the live-standby +# fast-failover path (which promotes via the coordinator, not start.sh) are unaffected. +if [[ -f "/var/pv/data/standby.signal" ]]; then + echo "standby.signal present -> promoting to fork a new timeline before writes" + pg_ctl -D "$PGDATA" promote || true + for _ in $(seq 1 120); do + state=$(pg_controldata "$PGDATA" 2>/dev/null | grep "Database cluster state" | sed 's/.*:[[:space:]]*//') + if [[ "$state" == "in production" ]]; then + echo "promotion complete; node is now primary on a new timeline" + break + fi + sleep 1 + done +fi + # create database with specified name if [ "$POSTGRES_DB" != "postgres" ]; then "${psql[@]}" --username postgres <<-EOSQL diff --git a/role_scripts/17/primary/start.sh b/role_scripts/17/primary/start.sh index fc05df8..d636bb6 100755 --- a/role_scripts/17/primary/start.sh +++ b/role_scripts/17/primary/start.sh @@ -95,6 +95,29 @@ export POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} psql=(psql -v ON_ERROR_STOP=1) +# If standby.signal is present, postgres started in recovery above (this node was a standby being +# promoted). Promote it NOW to fork a NEW timeline BEFORE any write below. This is essential for the +# remote-replica -> standalone-HA transition: without promoting from recovery the node comes up on +# the SAME timeline as its former source cluster, which on failback forces a full pg_basebackup +# instead of pg_rewind. Promotion ends recovery, increments the timeline, and removes standby.signal. +# A normal primary start (no standby.signal) skips this block, so fresh bootstrap and the live-standby +# fast-failover path (which promotes via the coordinator, not start.sh) are unaffected. +if [[ -f "/var/pv/data/standby.signal" ]]; then + echo "standby.signal present -> promoting to fork a new timeline before writes" + pg_ctl -D "$PGDATA" promote || true + # Wait until recovery has ended using pg_controldata (no DB connection / role dependency, so a + # missing or renamed superuser role can never stall this loop). State goes from + # "in archive recovery" to "in production" once promotion completes. + for _ in $(seq 1 120); do + state=$(pg_controldata "$PGDATA" 2>/dev/null | grep "Database cluster state" | sed 's/.*:[[:space:]]*//') + if [[ "$state" == "in production" ]]; then + echo "promotion complete; node is now primary on a new timeline" + break + fi + sleep 1 + done +fi + # create database with specified name if [ "$POSTGRES_DB" != "postgres" ]; then "${psql[@]}" --username postgres <<-EOSQL diff --git a/role_scripts/18/primary/start.sh b/role_scripts/18/primary/start.sh index c3ba065..7610a4a 100755 --- a/role_scripts/18/primary/start.sh +++ b/role_scripts/18/primary/start.sh @@ -95,6 +95,26 @@ export POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} psql=(psql -v ON_ERROR_STOP=1) +# If standby.signal is present, postgres started in recovery above (this node was a standby being +# promoted). Promote it NOW to fork a NEW timeline BEFORE any write below. This is essential for the +# remote-replica -> standalone-HA transition: without promoting from recovery the node comes up on +# the SAME timeline as its former source cluster, which on failback forces a full pg_basebackup +# instead of pg_rewind. Promotion ends recovery, increments the timeline, and removes standby.signal. +# A normal primary start (no standby.signal) skips this block, so fresh bootstrap and the live-standby +# fast-failover path (which promotes via the coordinator, not start.sh) are unaffected. +if [[ -f "/var/pv/data/standby.signal" ]]; then + echo "standby.signal present -> promoting to fork a new timeline before writes" + pg_ctl -D "$PGDATA" promote || true + for _ in $(seq 1 120); do + state=$(pg_controldata "$PGDATA" 2>/dev/null | grep "Database cluster state" | sed 's/.*:[[:space:]]*//') + if [[ "$state" == "in production" ]]; then + echo "promotion complete; node is now primary on a new timeline" + break + fi + sleep 1 + done +fi + # create database with specified name if [ "$POSTGRES_DB" != "postgres" ]; then "${psql[@]}" --username postgres <<-EOSQL