From 1c5d5f1daeadf3c899720f64765c7d3a6c05ad77 Mon Sep 17 00:00:00 2001 From: Alexander Kukushkin Date: Tue, 18 Apr 2017 12:45:24 +0200 Subject: [PATCH] BUGFIX: pg_drop_replication_slot may not be called if slot is active (#427) Default value of wal_sender_timeout is 60 seconds while we are trying to remove replication slot after 30 seconds (ttl=30). That means postgres might think that slot is still active and does nothing. Patroni at the same time was thinking that it was removed successfully. If the drop replication slot query didn't return any single row we must fetch list of existing physical replication slots from postgres on the next iteration of HA loop. Fixes: issue #425 --- patroni/postgresql.py | 9 ++++++--- tests/test_postgresql.py | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/patroni/postgresql.py b/patroni/postgresql.py index 185b5caf..4ce4cc51 100644 --- a/patroni/postgresql.py +++ b/patroni/postgresql.py @@ -1181,9 +1181,12 @@ $$""".format(name, ' '.join(options)), name, password, password) # drop unused slots for slot in set(self._replication_slots) - slots: - self._query("""SELECT pg_drop_replication_slot(%s) - WHERE EXISTS(SELECT 1 FROM pg_replication_slots - WHERE slot_name = %s AND NOT active)""", slot, slot) + cursor = self._query("""SELECT pg_drop_replication_slot(%s) + WHERE EXISTS(SELECT 1 FROM pg_replication_slots + WHERE slot_name = %s AND NOT active)""", slot, slot) + + if cursor.rowcount != 1: # Either slot doesn't exists or it is still active + self._schedule_load_slots = True # schedule load_replication_slots on the next iteration # create new slots for slot in slots - set(self._replication_slots): diff --git a/tests/test_postgresql.py b/tests/test_postgresql.py index 7f83b909..4481cb7e 100644 --- a/tests/test_postgresql.py +++ b/tests/test_postgresql.py @@ -19,6 +19,7 @@ class MockCursor(object): def __init__(self, connection): self.connection = connection self.closed = False + self.rowcount = 0 self.results = [] def execute(self, sql, *params):