Permanent replication slots (#819)

Permanent replication slots are preserved on failover/switchover, that is Patroni on the new primary will create configured replication slots right after doing promote.

Slots could be configured with the help of `patronictl edit-config`.
The initial configuration could be also done in the `bootstrap.dcs`

```yaml
slots:
  permanent_physical_1:
    type: physical
  permanent_logical_1:
    type: logical
    database: foo
    plugin: pgoutput
```

It is the responsibility of the operator to make sure that there are no clashes in names between replication slots automatically created by Patroni for members and permanent replication slots.

Closes https://github.com/zalando/patroni/issues/656
This commit is contained in:
Alexander Kukushkin
2018-10-31 11:37:42 +01:00
committed by GitHub
parent c65c4f1ffe
commit 2efd97baab
12 changed files with 267 additions and 109 deletions
+11 -21
View File
@@ -1,3 +1,4 @@
import os
import time
from behave import step
@@ -8,19 +9,13 @@ SELECT * FROM pg_catalog.pg_stat_replication
WHERE application_name = '{0}'
"""
create_replication_slot_query = """
SELECT pg_create_physical_replication_slot('{0}')
"""
@step('I start {name:w} without slots sync')
def start_patroni_without_slots_sync(context, name):
@step('I start {name:w} with callback configured')
def start_patroni_with_callbacks(context, name):
return context.pctl.start(name, custom_config={
"bootstrap": {
"dcs": {
"postgresql": {
"use_slots": False
}
"postgresql": {
"callbacks": {
"on_role_change": "features/callback.sh"
}
}
})
@@ -35,6 +30,10 @@ def start_patroni(context, name, cluster_name):
@step('I start {name:w} in a standby cluster {cluster_name:w} as a clone of {name2:w}')
def start_patroni_stanby_cluster(context, name, cluster_name, name2):
ctl = context.pctl._processes.pop(name, None)
# we need to remove patroni.dynamic.json in order to "bootstrap" standby cluster with existing PGDATA
if ctl:
os.unlink(os.path.join(ctl._data_dir, 'patroni.dynamic.json'))
port = context.pctl._processes[name2]._connkwargs.get('port')
return context.pctl.start(name, custom_config={
"scope": cluster_name,
@@ -43,7 +42,7 @@ def start_patroni_stanby_cluster(context, name, cluster_name, name2):
"standby_cluster": {
"host": "localhost",
"port": port,
"primary_slot_name": "postgres1",
"primary_slot_name": "pm_1",
}
}
}
@@ -67,12 +66,3 @@ def check_replication_status(context, pg_name1, pg_name2, timeout):
time.sleep(1)
return False
@step('I create a replication slot {slot_name:w} on {pg_name:w}')
def create_replication_slot(context, slot_name, pg_name):
return context.pctl.query(
pg_name,
create_replication_slot_query.format(slot_name),
fail_ok=True
)