<!--
Les sources pour ce sujet sont :

* Enable the failover of logical slots (Hou Zhijie, Shveta Malik, Ajin Cherian)
  + https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=c393308b6
* Add the failover property to the replication protocol (Hou Zhijie, Shveta Malik)
  + https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=732924043
* Add function pg_sync_replication_slots() to synchronize logical replication slots (Hou Zhijie, Shveta Malik, Ajin Cherian, Peter Eisentraut)
  + https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=ddd5f4f54 Feature
  + https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=7a424ece4 Ajout msgs
* Add server variable sync_replication_slots to enable failover logical slot synchronization (Shveta Malik, Hou Zhijie, Peter Smith)
  + https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=93db6cbda Feature
  + https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=60c07820d Patch doc

Discussion :

* Enable the failover of logical slots (Hou Zhijie, Shveta Malik, Ajin Cherian)
  + https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
* Add the failover property to the replication protocol (Hou Zhijie, Shveta Malik)
  + https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
* Add function pg_sync_replication_slots() to synchronize logical replication slots (Hou Zhijie, Shveta Malik, Ajin Cherian, Peter Eisentraut)
  + https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
  + https://postgr.es/m/OS0PR01MB571633C23B2A4CAC5FB0371A944C2@OS0PR01MB5716.jpnprd01.prod.outlook.com
* Add server variable sync_replication_slots to enable failover logical slot synchronization (Shveta Malik, Hou Zhijie, Peter Smith)
  + https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
  + https://postgr.es/m/CAHut+Ps01fV9bjhj6njCFiHu0W0gu1Jcu0tKo0RYMhHx-hZZ7g@mail.gmail.com

-->

<div class="slide-content">

  * Option `failover`
    + `pg_create_logical_replication_slot()`,
    + `CREATE SUBSCRIPTION`
  * Synchronisation des slots de réplication
    + `pg_sync_replication_slots()`
  * Fonction `sync_replication_slots`
    + automatiser la synchronisation

</div>

<div class="notes">

Cette version de PostgreSQL introduit une fonctionnalité qui manquait à la
réplication logique depuis longtemps : la possibilité de maintenir la
réplication logique malgré un switchover de la réplication physique sur la
grappe de serveurs _provider_. Nous allons détailler ici les différents
éléments qui constituent cette fonctionnalité.

Note : pour pouvoir exécuter les commandes ci-dessous, il faut configurer le
paramètre `wal_level` à `logical`.

*Propriété failover sur les slots de réplications*

La fonction `pg_create_logical_replication_slot()` s'est vu ajoutée un nouveau
paramètre `failover` :

```sql
\df pg_create_logical_replication_slot()
```

\small

```console
                              List of functions
                Name                |                  Argument data types
------------------------------------+--------------------------------------------------------------
 pg_create_logical_replication_slot | slot_name name, plugin name, temporary boolean DEFAULT false,
                                    | twophase boolean DEFAULT false, failover DEFAULT false,
                                    | OUT slot_name name, OUT lsn pg_lsn
(1 row)
```

\normalsize

Cette propriété indique que le slot de réplication logique sera synchronisé sur
l'instance secondaire d'un dispositif de réplication physique, ce qui
permettra de reprendre la réplication logique en cas de switchover.

La vue `pg_replication_slots` a également été mise à jour afin de refléter
la présence de cette propriété.

```sql
SELECT slots.*
  FROM (VALUES ('rl_test_f', true),('rl_test_nof', false)) AS slot(name, has_failover)
       CROSS JOIN LATERAL pg_create_logical_replication_slot(name, 'test_decoding', failover=>has_failover) AS slots;
```
```console
  slot_name   |    lsn
--------------+-----------
 rl_test_f    | 0/1AFD380
 rl_test_nof  | 0/1AFD3B8
(2 rows)
```
```sql
SELECT slot_name, slot_type, failover FROM pg_replication_slots ;
```
```console
  slot_name   | slot_type | failover
--------------+-----------+----------
 rl_test_f    | logical   | t
 rl_test_nof  | logical   | f
(2 rows)
```
```sql
SELECT pg_drop_replication_slot(name)
  FROM (VALUES ('rl_test_f'),('rl_test_nof')) AS slot(name);
```

L'option a également été ajoutée au protocole de réplication.

```bash
psql "dbname=postgres replication=database" <<_EOF_
CREATE_REPLICATION_SLOT test LOGICAL test_decoding (FAILOVER true);
SELECT slot_name, slot_type, failover FROM pg_replication_slots ;
_EOF_
```
```console
 slot_name | consistent_point |    snapshot_name    | output_plugin
-----------+------------------+---------------------+---------------
 test      | 0/1AFD460        | 00000074-00000002-1 | test_decoding
(1 row)

 slot_name | slot_type | failover
-----------+-----------+----------
 test      | logical   | t
(1 row)
```

Une nouvelle commande a été ajoutée au protocole de réplication pour mettre à
jour un slot :

```bash
psql "dbname=postgres replication=database" <<_EOF_
ALTER_REPLICATION_SLOT test (FAILOVER false);
SELECT slot_name, slot_type, failover FROM pg_replication_slots ;
_EOF_
```
```console
ALTER_REPLICATION_SLOT
 slot_name | slot_type | failover
-----------+-----------+----------
 test      | logical   | f
(1 row)
```
```bash
psql "dbname=postgres replication=database" <<_EOF_
DROP_REPLICATION_SLOT test;
_EOF_
```

Ces mises à jour du protocole permettent à une standby de demander au
_walsender_ de créer / mettre à jour un slot et définir sa propriété
`failover`.

*Capacité de synchroniser des slots depuis une standby*

L'étape suivante dans le développement de cette fonctionnalité a été de mettre
en place la synchronisation des slots de réplications. Cette fonctionnalité
ajoute des contraintes à la mise en place de la réplication physique :

* la réplication physique doit utiliser un slot de réplication. Les efforts
  réalisés pour invalider les slots si les standbys ne consomment pas les slots
  et améliorer les vues de supervision, font que ce n'est pas un risque pour la
  disponibilité du service sur l'instance primaire ;

* le `hot_standby_feedback` doit être activé. Cela peut avoir un impact sur
  le nettoyage des lignes mortes sur la primaire si des requêtes longues sont
  lancées sur la standby.

* la chaine de connexion spécifiée dans `primary_conninfo` doit contenir un nom
  de base de données valide.

Pour utiliser la synchronisation des slots, il faut :

* créer un slot sur la primaire avec l'attribut `failover` configuré à `true` ;

* utiliser l'option `failover` de la commande `CREATE SUBSCRIPTION` sur le
  serveur souscripteur.

Il faudra ensuite exécuter la fonction `pg_sync_replication_slots()` pour
forcer la synchronisation du slot.

Une nouvelle colonne `synched` a été ajoutée à la vue `pg_replication_slots`
pour indiquer que le slot est un slot synchronisé avec la primaire. En
situation normale, il ne devrait donc pas y avoir de slots `synched` sur une
instance primaire.

Un slot synchronisé ne peut pas être supprimé et son contenu ne peut pas être
consommé.

Si le slot de réplication logique de l'instance primaire est invalidé, le slot
synchronisé sur la secondaire sera également invalidé.

Si le slot de réplication logique de l'instance secondaire est invalidé sur la
standby, il sera supprimé. Il faudra relancer la commande
`pg_sync_replication_slots()` pour le recréer. Cette invalidation peut être due
au fait que le `max_slot_wal_keep_size` de la standby est insuffisant pour
retenir les enregistrements de WAL nécessaire pour satisfaire le
`restart_lsn` du slot ou que le `primary_slot_name` a été supprimé.

Voici un exemple réalisé sous FEDORA avec PGDATAS=`~/tmp/failover` et
`PGUSER=postgres`, le logging collector est activé, les sockets sont créés dans
'/tmp', les traces et la configuration sont dans le répertoire de données.
Toutes les connexions sont faites via les sockets, pour qui la méthode
d'authentification est `trust` (donc pas d'authentification).

* mise en place d'une instance primaire :

  ```sql
  initdb --pgdata=$PGDATAS/primaire \
         --set port=5495 \
         --set wal_level=logical \
         --set cluster_name=primaire \
         --username=postgres
  pg_ctl start --pgdata $PGDATAS/primaire
  createuser replicator --replication --port=5495
  ```

* mise en place d'une instance secondaire :

  ```sql
  pg_basebackup --pgdata $PGDATAS/secondaire \
                --progress --checkpoint=fast \
                --create-slot \
                --slot=secondaire \
                --dbname="port=5495 user=replicator"
  rm -f $PGDATAS/secondaire/log/*
  touch $PGDATAS/secondaire/standby.signal
  cat >> $PGDATAS/secondaire/postgresql.conf <<_EOF_
  port = 5496
  cluster_name = secondaire
  primary_conninfo = 'port=5495 user=replicator dbname=postgres application_name=secondaire'
  primary_slot_name = 'secondaire'
  hot_standby_feedback = on
  _EOF_
  pg_ctl start --pgdata $PGDATAS/secondaire
  ```

* vérification de la réplication : les _walsenders_ et _walreceiver_ sont
  présents et la primaire est au statut streaming.

  ```sql
  ps f -ee | grep -E "(primaire|secondaire)"
  ```
  ```console
  300207 ?        Ss     0:00  \_ /usr/pgsql-17/bin/postgres -D /home/benoit/tmp/failover/primaire
  300208 ?        Ss     0:00  |   \_ postgres: primaire: logger
  300209 ?        Ss     0:00  |   \_ postgres: primaire: checkpointer
  300210 ?        Ss     0:00  |   \_ postgres: primaire: background writer
  300212 ?        Ss     0:00  |   \_ postgres: primaire: walwriter
  300213 ?        Ss     0:00  |   \_ postgres: primaire: autovacuum launcher
  300214 ?        Ss     0:00  |   \_ postgres: primaire: logical replication launcher
  303235 ?        Ss     0:00  |   \_ postgres: primaire: walsender replicator [local] streaming 0/B000168
  303229 ?        Ss     0:00  \_ /usr/pgsql-17/bin/postgres -D /home/benoit/tmp/failover/secondaire
  303230 ?        Ss     0:00      \_ postgres: secondaire: logger
  303231 ?        Ss     0:00      \_ postgres: secondaire: checkpointer
  303232 ?        Ss     0:00      \_ postgres: secondaire: background writer
  303233 ?        Ss     0:00      \_ postgres: secondaire: startup recovering 00000001000000000000000B
  303234 ?        Ss     0:00      \_ postgres: secondaire: walreceiver streaming 0/B000168
  ```

* création d'un slot de réplication synchronisé et synchronisation :

  ```psql
  psql -p 5495 -c "SELECT pg_create_logical_replication_slot('test_sync', 'pgoutput', failover=>'true');"
  psql -p 5496 -c "SELECT pg_sync_replication_slots();"
  ```

* Vérifications :

  ```psql
  psql <<_EOF_
  \c postgres postgres /tmp 5495
  SELECT slot_name, slot_type, failover, synced FROM pg_replication_slots;
  \c postgres postgres /tmp 5496
  SELECT slot_name, slot_type, failover, synced FROM pg_replication_slots;
  _EOF_
  ```
  ```console
  You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5495".
   slot_name  | slot_type | failover | synced
  ------------+-----------+----------+--------
   secondaire | physical  | f        | f
   test_sync  | logical   | t        | f
  (2 rows)

  You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5496".
   slot_name | slot_type | failover | synced
  -----------+-----------+----------+--------
   test_sync | logical   | t        | t
  (1 row)
  ```

  On voit que le slot est synchronisé sur la standby et que l'option `failover`
  est activée.

  Comme promis, il n'est pas possible de supprimer le slot directement sur la
  standby.

  ```bash
  psql <<_EOF_
  -- serveur de secondaire
  \c postgres postgres /tmp 5496
  SELECT pg_drop_replication_slot('test_sync');
  -- serveur de primaire
  \c postgres postgres /tmp 5495
  SELECT pg_drop_replication_slot('test_sync');
  _EOF_
  ```
  ```console
  You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5496".
  ERROR:  cannot drop replication slot "test_sync"
  DETAIL:  This replication slot is being synchronized from the primary server.
  You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5495".
   pg_drop_replication_slot
  --------------------------
  ```

  Une fois le slot supprimé sur la primaire, le slot est encore visible sur la
  standby. Il faut utiliser la fonction `pg_sync_replication_slots()` sur la
  standby pour le faire disparaitre.

  ```bash
  psql <<_EOF_
  -- serveur de primaire
  \c postgres postgres /tmp 5495
  SELECT slot_name, slot_type, failover, synced FROM pg_replication_slots;
  -- serveur de secondaire
  \c postgres postgres /tmp 5496
  SELECT slot_name, slot_type, failover, synced FROM pg_replication_slots;
  _EOF_
  ```
  ```console
  You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5495".
   slot_name  | slot_type | failover | synced
  ------------+-----------+----------+--------
   secondaire | physical  | f        | f
  (1 row)

  You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5496".
   slot_name | slot_type | failover | synced
  -----------+-----------+----------+--------
   test_sync | logical   | t        | t
  (1 row)
  ```
  ```bash
  psql -p 5496 <<_EOF_
  SELECT pg_sync_replication_slots();
  SELECT slot_name, slot_type, failover, synced FROM pg_replication_slots;
  _EOF_
  ```
  ```console
  You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5496".
   slot_name | slot_type | failover | synced
  -----------+-----------+----------+--------
  (0 rows)
  ```

  * mise en place de la publication :

  ```bash
  psql -p 5495 -c "CREATE PUBLICATION pub FOR TABLES IN SCHEMA public;"
  ```

  * création d'une souscription et de l'instance associée :

  ```sql
  initdb --pgdata=$PGDATAS/souscription \
         --set port=5497 \
         --set cluster_name=souscription \
         --username=postgres
  pg_ctl start --pgdata $PGDATAS/souscription
  psql <<_EOF_
  -- serveur de souscription
  \c postgres postgres /tmp 5497
  CREATE SUBSCRIPTION sub
    CONNECTION 'port=5495 dbname=postgres'
    PUBLICATION pub
    WITH (failover);
  -- serveur de secondaire
  \c postgres postgres /tmp 5496
  SELECT pg_sync_replication_slots();
  _EOF_
  ```

  * vérifications :

  ```bash
  psql <<_EOF_
  \c postgres postgres /tmp 5497
  \x
  \dRs+
  \x
  \c postgres postgres /tmp 5495
  SELECT slot_name, slot_type, failover, synced FROM pg_replication_slots;
  \c postgres postgres /tmp 5496
  SELECT slot_name, slot_type, failover, synced FROM pg_replication_slots;
  _EOF_
  ```
  ```console
  List of subscriptions
  -[ RECORD 1 ]------+------------------------------------------
  Name               | sub
  Owner              | postgres
  Enabled            | t
  Publication        | {pub}
  Binary             | f
  Streaming          | off
  Two-phase commit   | d
  Disable on error   | f
  Origin             | any
  Password required  | t
  Run as owner?      | f
  Failover           | t
  Synchronous commit | off
  Conninfo           | port=5495 user=replicator dbname=postgres
  Skip LSN           | 0/0
  You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5495".
   slot_name  | slot_type | failover | synced
  ------------+-----------+----------+--------
   secondaire | physical  | f        | f
   sub        | logical   | t        | f
  (2 rows)

  You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5496".
   slot_name | slot_type | failover | synced
  -----------+-----------+----------+--------
   sub       | logical   | t        | t
  (1 row)
  ```

  Si on supprime le slot, il faut aussi relancer `pg_sync_replication_slots()`
  sur la standby.

  ```bash
  psql <<_EOF_
  -- serveur de souscription
  \c postgres postgres /tmp 5497
  DROP SUBSCRIPTION sub;
  -- serveur de secondaire
  \c postgres postgres /tmp 5496
  SELECT pg_sync_replication_slots();
  _EOF_
  ```

*Synchronisation automatique des slots*

La synchronisation des slots peut être automatiquement réalisée en activant le
paramètre `sync_replication_slots` sur l'instance secondaire.

Nous allons l'activer sur les deux instances puisque l'objectif est de réaliser
un switchover.

```bash
echo "sync_replication_slots = true" >> $PGDATAS/primaire/postgresql.conf
pg_ctl restart -D $PGDATAS/primaire
echo "sync_replication_slots = true" >> $PGDATAS/secondaire/postgresql.conf
pg_ctl restart -D $PGDATAS/secondaire
```

On peut observer qu'un processus `slotsync worker` est démarré sur la standby :

```bash
ps f -e | grep -E "(primaire|secondaire)"
```
```console
316406 ?        Ss     0:00  \_ /usr/pgsql-17/bin/postgres -D /home/benoit/tmp/failover/primaire
316407 ?        Ss     0:00  |   \_ postgres: primaire: logger
316409 ?        Ss     0:00  |   \_ postgres: primaire: checkpointer
316410 ?        Ss     0:00  |   \_ postgres: primaire: background writer
316412 ?        Ss     0:00  |   \_ postgres: primaire: walwriter
316413 ?        Ss     0:00  |   \_ postgres: primaire: autovacuum launcher
316414 ?        Ss     0:00  |   \_ postgres: primaire: logical replication launcher
316441 ?        Ss     0:00  |   \_ postgres: primaire: walsender replicator [local] streaming 0/B0063C0
316442 ?        Ss     0:00  |   \_ postgres: primaire: replicator postgres [local] idle
316434 ?        Ss     0:00  \_ /usr/pgsql-17/bin/postgres -D /home/benoit/tmp/failover/secondaire
316435 ?        Ss     0:00      \_ postgres: secondaire: logger
316436 ?        Ss     0:00      \_ postgres: secondaire: checkpointer
316437 ?        Ss     0:00      \_ postgres: secondaire: background writer
316438 ?        Ss     0:00      \_ postgres: secondaire: startup recovering 00000001000000000000000B
316439 ?        Ss     0:00      \_ postgres: secondaire: walreceiver streaming 0/B0063C0
316440 ?        Ss     0:00      \_ postgres: secondaire: slotsync worker
```

Recréons un slot de réplication :

```bash
psql -p 5497 <<_EOF_
CREATE SUBSCRIPTION sub
  CONNECTION 'port=5495 dbname=postgres'
  PUBLICATION pub
  WITH (failover);
_EOF_
```

La synchronisation des slots de réplication logique n'est pas instantanée, le
`slotsync worker` se réveille à intervalle régulier et récupère les
informations concernant les slots de réplication pour les créer ou les mettre
à jour. La durée de repos du processus est adaptée en fonction de l'activité
sur la primaire.

Après une période d'attente, le slot apparaît sur la secondaire :

```bash
psql <<_EOF_
\c postgres postgres /tmp 5497
\x
\dRs+
\x
\c postgres postgres /tmp 5495
SELECT slot_name, slot_type, failover, synced FROM pg_replication_slots;
\c postgres postgres /tmp 5496
SELECT slot_name, slot_type, failover, synced FROM pg_replication_slots;
_EOF_
```
```console
You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5497".
Expanded display is on.
List of subscriptions
-[ RECORD 1 ]------+------------------------------------------
Name               | sub
Owner              | postgres
Enabled            | t
Publication        | {pub}
Binary             | f
Streaming          | off
Two-phase commit   | d
Disable on error   | f
Origin             | any
Password required  | t
Run as owner?      | f
Failover           | t
Synchronous commit | off
Conninfo           | port=5495 user=replicator dbname=postgres
Skip LSN           | 0/0

Expanded display is off.
You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5495".
 slot_name  | slot_type | failover | synced
------------+-----------+----------+--------
 secondaire | physical  | f        | f
 sub        | logical   | t        | f
(2 rows)

You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5496".
 slot_name | slot_type | failover | synced
-----------+-----------+----------+--------
 sub       | logical   | t        | t
(1 row)
```

*Insertions de données*

```bash
psql <<_EOF_
-- primaire / publication
\c postgres postgres /tmp 5495
CREATE TABLE junk(i int, t text);
INSERT INTO junk SELECT x, 'texte '||x FROM generate_series(1,10000) AS F(x);
-- souscription
\c postgres postgres /tmp 5497
CREATE TABLE junk(i int, t text);
ALTER SUBSCRIPTION sub REFRESH PUBLICATION;
SELECT pg_sleep_for(INTERVAL '2s');
SELECT count(*) FROM junk;
_EOF_
```
```bash
psql <<_EOF_
-- primaire / publication
\c postgres postgres /tmp 5495
SELECT slot_name, slot_type, failover, synced, restart_lsn FROM pg_replication_slots;
-- secondaire
\c postgres postgres /tmp 5496
SELECT slot_name, slot_type, failover, synced, restart_lsn FROM pg_replication_slots;
_EOF_
```
```console
You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5495".
 slot_name  | slot_type | failover | synced | restart_lsn
------------+-----------+----------+--------+-------------
 secondaire | physical  | f        | f      | 0/3129A40
 sub        | logical   | t        | f      | 0/3129A08
(2 rows)

You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5496".
 slot_name | slot_type | failover | synced | restart_lsn
-----------+-----------+----------+--------+-------------
 sub       | logical   | t        | t      | 0/3129A08
(1 row)
```

*Bascule controlée de la réplication (switchover)*

Arrêter la primaire :

```bash
# primaire
pg_ctl stop -D $PGDATAS/primaire -m fast -w
pg_controldata -D $PGDATAS/primaire |\
  grep -E "(Database cluster state|Latest checkpoint's REDO location)"
```

Vérifier que la standby a tout reçu et la promouvoir :

```bash
# secondaire > nouvelle primaire
psql -p 5496 -c "CHECKPOINT;"
pg_controldata -D $PGDATAS/secondaire |\
  grep -E "(Database cluster state|Latest checkpoint's REDO location)"
pg_ctl promote -D $PGDATAS/secondaire
echo "cluster_name = 'nouvelle primaire'" >> $PGDATAS/secondaire/postgresql.conf
psql -p 5496 -c "SELECT pg_create_physical_replication_slot('ancienne_primaire');"
pg_ctl restart -D $PGDATAS/secondaire # pour màj les titres de processus pour la démo
psql -p 5496 -c "INSERT INTO junk SELECT x, 'texte '||x FROM generate_series(1,10000) AS F(x);"
```

Reconnecter l'ancienne primaire :

```bash
# ancienne primaire
touch $PGDATAS/primaire/standby.signal
cat >> $PGDATAS/primaire/postgresql.conf <<_EOF_
primary_conninfo = 'port=5496 user=replicator dbname=postgres application_name=ancienne_primaire'
primary_slot_name = 'ancienne_primaire'
hot_standby_feedback = on
cluster_name = 'ancienne primaire'
_EOF_
pg_ctl start -D $PGDATAS/primaire
```

Il faut ensuite mettre à jour la souscription :

```bash
psql -p 5497 -c "ALTER SUBSCRIPTION sub CONNECTION 'port=5496 dbname=postgres';"
```

... et supprimer les slot  sur l'ancienne primaire :
```bash
psql -p 5495 -c "SELECT pg_drop_replication_slot('sub');"
psql -p 5495 -c "SELECT pg_drop_replication_slot('secondaire');"
```
La réplication logique a bien basculé :

```bash
ps f -e | grep -E "(primaire|secondaire|souscription)"
```
```console
330608 ?        Ss     0:00  \_ /usr/pgsql-17/bin/postgres -D /home/benoit/tmp/failover/souscription
330609 ?        Ss     0:00  |   \_ postgres: souscription: logger
330610 ?        Ss     0:00  |   \_ postgres: souscription: checkpointer
330611 ?        Ss     0:00  |   \_ postgres: souscription: background writer
330613 ?        Ss     0:00  |   \_ postgres: souscription: walwriter
330614 ?        Ss     0:00  |   \_ postgres: souscription: autovacuum launcher
330615 ?        Ss     0:00  |   \_ postgres: souscription: logical replication launcher
335150 ?        Ss     0:00  |   \_ postgres: souscription: logical replication apply worker for subscription 16384
333983 ?        Ss     0:00  \_ /usr/pgsql-17/bin/postgres -D /home/benoit/tmp/failover/primaire
333984 ?        Ss     0:00  |   \_ postgres: ancienne primaire: logger
333985 ?        Ss     0:00  |   \_ postgres: ancienne primaire: checkpointer
333986 ?        Ss     0:00  |   \_ postgres: ancienne primaire: background writer
333987 ?        Ss     0:00  |   \_ postgres: ancienne primaire: startup recovering 000000020000000000000003
334439 ?        Ss     0:00  |   \_ postgres: ancienne primaire: walreceiver streaming 0/31E1B50
336165 ?        Ss     0:00  |   \_ postgres: ancienne primaire: slotsync worker
334371 ?        Ss     0:00  \_ /usr/pgsql-17/bin/postgres -D /home/benoit/tmp/failover/secondaire
334372 ?        Ss     0:00      \_ postgres: nouvelle primaire: logger
334373 ?        Ss     0:00      \_ postgres: nouvelle primaire: checkpointer
334374 ?        Ss     0:00      \_ postgres: nouvelle primaire: background writer
334376 ?        Ss     0:00      \_ postgres: nouvelle primaire: walwriter
334377 ?        Ss     0:00      \_ postgres: nouvelle primaire: autovacuum launcher
334378 ?        Ss     0:00      \_ postgres: nouvelle primaire: logical replication launcher
334440 ?        Ss     0:00      \_ postgres: nouvelle primaire: walsender replicator [local] streaming 0/31E1B50
335156 ?        Ss     0:00      \_ postgres: nouvelle primaire: walsender postgres postgres [local] START_REPLICATION
336169 ?        Ss     0:00      \_ postgres: nouvelle primaire: replicator postgres [local] idle
```

Les données ont bien été synchronisées :

```bash
psql <<_EOF_
-- nouvelle primaire / publication
\c postgres postgres /tmp 5496
INSERT INTO junk SELECT x, 'texte '||x FROM generate_series(1,10000) AS F(x);
SELECT count(*) FROM junk;
-- souscription
\c postgres postgres /tmp 5497
SELECT pg_sleep_for(INTERVAL '2s');
SELECT count(*) FROM junk;
_EOF_
```
```console
_EOF_
You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5496".
INSERT 0 10000
 count
-------
 30000
(1 row)

You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5497".
 pg_sleep_for
--------------

(1 row)

 count
-------
 30000
(1 row)
```

*Bascule non programmée (failover)*

Si une bascule non programmée est réalisée et que pour une raison ou pour une
autre les deux instances divergent, il est possible que la souscription reçoive
des informations qui ne sont pas arrivées sur la nouvelle instance primaire.
Cela pourrait causer des conflits de réplication logique par la suite et/ou
provoquer des bugs au niveau applicatif.

<!-- Démo pr mémo

Même setup que le TP 10000 lignes dans `junk`.

Promotion a la sauvage de la standby :

```bash
~/tmp/failover took 8s
❯  pg_ctl promote -D secondaire/
waiting for server to promote.... done
server promoted
```

Écriture sur l'ancienne primaire pour simuler des écritures qui ne sont pas
arrivées sur la nouvelle primaire :

```bash
~/tmp/failover
❯ psql -p 5495 -c "INSERT INTO junk VALUES (NULL, 'FAKE');"
INSERT 0 1

~/tmp/failover
❯  pg_ctl stop -D primaire/
waiting for server to shut down.... done
server stopped
```

Rebranchement sur la souscription sur la publication de la nouvelle primaire :

```bash
~/tmp/failover
❯ psql -p 5497 -c "ALTER SUBSCRIPTION sub CONNECTION 'port=5496 dbname=postgres';"
ALTER SUBSCRIPTION
```

Écriture sur la nouvelle primaire :

```
~/tmp/failover
❯ psql -p 5496 -c "INSERT INTO junk VALUES (NULL, '(re) NEW');"
INSERT 0 1
```

La ligne "FAKE" n'est pas la (normal) :

```bash
~/tmp/failover
❯ psql -p 5496 -c "SELECT * FROM junk WHERE i IS NULL"
 i |    t
---+----------
 ¤ | (re) NEW
(1 row)
```

Les écritures passent bien sur la souscription :

```bash
/tmp/failover
❯ psql -p 5497 -c "SELECT * FROM junk WHERE i IS NULL"
 i |    t
---+----------
 ¤ | FAKE
 ¤ | (re) NEW
(2 rows)

~/tmp/failover
❯ psql -p 5497 -c "SELECT count(*) FROM junk"
 count
-------
 10002
(1 row)
```
-->
</div>
