diff --git a/patroni/postgresql/slots.py b/patroni/postgresql/slots.py index c7e94239..e8ae8a18 100644 --- a/patroni/postgresql/slots.py +++ b/patroni/postgresql/slots.py @@ -95,8 +95,8 @@ class SlotsAdvanceThread(Thread): self._failed = True new_lsn = self._scheduled.get(database, {}).get(slot, 0) - # remove slot from the self._scheduled structure only if it wasn't changed - if new_lsn == lsn and database in self._scheduled: + # remove slot from the self._scheduled structure if it is to be copied or if it wasn't changed + if copy or (new_lsn == lsn and database in self._scheduled): self._scheduled[database].pop(slot) if not self._scheduled[database]: self._scheduled.pop(database) @@ -152,7 +152,10 @@ class SlotsAdvanceThread(Thread): """ with self._condition: for database, values in advance_slots.items(): - self._scheduled[database].update(values) + for name, value in values.items(): + # Don't schedule sync for slots that just failed to be advanced and scheduled to be copied + if name not in self._copy_slots: + self._scheduled[database][name] = value ret = (self._failed, self._copy_slots) self._copy_slots = [] self._failed = False @@ -160,7 +163,7 @@ class SlotsAdvanceThread(Thread): return ret - def on_promote(self) -> None: + def clean(self) -> None: """Reset state of the daemon.""" with self._condition: self._scheduled.clear() @@ -675,6 +678,8 @@ class SlotsHandler: logger.error("Failed to copy logical slots from the %s via postgresql connection: %r", leader.name, e) if copy_slots and self._postgresql.stop(): + if self._advance: + self._advance.clean() pg_perm.set_permissions_from_data_directory(self._postgresql.data_dir) for name, value in copy_slots.items(): slot_dir = os.path.join(self.pg_replslot_dir, name) @@ -718,7 +723,7 @@ class SlotsHandler: """ if self._advance: - self._advance.on_promote() + self._advance.clean() if self._logical_slots_processing_queue: logger.warning('Logical replication slots that might be unsafe to use after promote: %s', diff --git a/tests/test_slots.py b/tests/test_slots.py index 694940f1..3d5a7cee 100644 --- a/tests/test_slots.py +++ b/tests/test_slots.py @@ -274,6 +274,10 @@ class TestSlotsHandler(BaseTestPostgresql): self.s.schedule_advance_slots({'foo': {'bar': 100}}) self.s._advance.sync_slots() self.assertEqual(self.s._advance._copy_slots, ["bar"]) + # we don't want to make attempts to advance slots that are to be copied + self.s.schedule_advance_slots({'foo': {'bar': 101}}) + self.assertEqual(self.s._advance._scheduled, {}) + self.s._advance.clean() with patch.object(SlotsAdvanceThread, 'sync_slots', Mock(side_effect=Exception)): self.s._advance._condition.wait = Mock()