From f28b2f5bc0509b25f2780eb2a9250d298449d27f Mon Sep 17 00:00:00 2001 From: vvsos1 Date: Fri, 28 Aug 2026 19:03:22 +0900 Subject: [PATCH] Fix PostgreSQL polling checkpoint updates --- pgsync/sync.py | 6 ++++++ tests/test_sync_polling.py | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/pgsync/sync.py b/pgsync/sync.py index d13dab52..36284d48 100644 --- a/pgsync/sync.py +++ b/pgsync/sync.py @@ -2020,6 +2020,12 @@ def pull(self, polling: bool = False) -> None: self.index, self.sync(txmin=txmin, txmax=txmax) ) + # PostgreSQL polling uses only the forward pass and has no logical + # replication slot, so advance its safe snapshot checkpoint directly. + if polling and not self.is_mysql_compat: + self.checkpoint = snapshot_xmin + return + if self.is_mysql_compat: self.binlog_changes( start_log=start_log, diff --git a/tests/test_sync_polling.py b/tests/test_sync_polling.py index 05567907..393f6167 100644 --- a/tests/test_sync_polling.py +++ b/tests/test_sync_polling.py @@ -19,6 +19,29 @@ def make_sync(): ) +def test_pull_polling_updates_checkpoint_without_logical_slot(): + """PostgreSQL polling must not depend on logical replication.""" + docs = [{"_id": "1"}] + sync = SimpleNamespace( + is_mysql_compat=False, + checkpoint=1, + txid_snapshot_xmin=100, + txid_current=200, + current_wal_lsn="0/16B6C50", + index="testdb", + search_client=Mock(), + sync=Mock(return_value=docs), + logical_slot_changes=Mock(), + _truncate=False, + ) + + Sync.pull(sync, polling=True) + + assert sync.checkpoint == 100 + sync.logical_slot_changes.assert_not_called() + sync.search_client.bulk.assert_called_once_with("testdb", docs) + + def test_poll_db_once_flushes_buffer_when_notification_wait_times_out(): sync = make_sync() conn = Mock()