diff --git a/patroni/ha.py b/patroni/ha.py index f91e93be..28bd92a3 100644 --- a/patroni/ha.py +++ b/patroni/ha.py @@ -656,11 +656,20 @@ class Ha(object): promoting standbys that were guaranteed to be replicating synchronously. """ if self.is_synchronous_mode(): - current = CaseInsensitiveSet(self.cluster.sync.members) + sync = self.cluster.sync + if sync.is_empty: + # corner case: we need to explicitly enable synchronous mode by updating the + # ``/sync`` key with the current leader name and empty members. In opposite case + # it will never be automatically enabled if there are not eligible candidates. + sync = self.dcs.write_sync_state(self.state_handler.name, None, version=sync.version) + if not sync: + return logger.warning("Updating sync state failed") + logger.info("Enabled synchronous replication") + + current = CaseInsensitiveSet(sync.members) picked, allow_promote = self.state_handler.sync_handler.current_state(self.cluster) if picked != current: - sync = self.cluster.sync # update synchronous standby list in dcs temporarily to point to common nodes in current and picked sync_common = current & allow_promote if sync_common != current: diff --git a/tests/test_ha.py b/tests/test_ha.py index f7378b43..6acb2e15 100644 --- a/tests/test_ha.py +++ b/tests/test_ha.py @@ -1294,6 +1294,19 @@ class TestHa(PostgresInit): mock_restart.assert_called_once() self.ha.dcs.get_cluster.assert_not_called() + def test_enable_synchronous_mode(self): + self.ha.is_synchronous_mode = true + self.ha.has_lock = true + self.p.name = 'leader' + self.ha.dcs.write_sync_state = Mock(return_value=SyncState.empty()) + with patch('patroni.ha.logger.info') as mock_logger: + self.ha.run_cycle() + self.assertEqual(mock_logger.call_args[0][0], 'Enabled synchronous replication') + self.ha.dcs.write_sync_state = Mock(return_value=None) + with patch('patroni.ha.logger.warning') as mock_logger: + self.ha.run_cycle() + self.assertEqual(mock_logger.call_args[0][0], 'Updating sync state failed') + def test_effective_tags(self): self.ha._disable_sync = True self.assertEqual(self.ha.get_effective_tags(), {'foo': 'bar', 'nosync': True})