mirror of
https://github.com/outbackdingo/patroni.git
synced 2026-08-25 14:53:37 +00:00
Don't allow stale primary to win the leader race (#2787)
Consider a following situation: 1. node1 is stressed so much that Patroni heart-beat can't run regularly and the leader lock expires. 2. node2 notice that there is no leader, gets the lock, promotes, and gets to a situation like it is described in 1. 3. Patroni on node1 finally wakes up, notice that Postgres is running as a primary, but without a leader lock and "happily" acquires the lock. That is, node1 discarded promoting of node2, and the node2 after that it will not be possible to join the node2 back to the cluster, because pg_rewind is not possible when two nodes are on the same timeline. To partially mitigate the problem we introduce an additional timeline check. If postgres is running as primary Patroni will consider it as a perfect candidate only if timeline isn't behind the last known cluster timeline recorder in the `/history` key. If postgres timeline is behind the cluster timeline postgres will be demoted to read-only. Further behavior would depend on `maximum_lag_on_failover` and `check_timeline` settings. Since the `/history` key isn't updated instantly after promotion, there is still a short period of time when the issue could happen, but it seems that it is close to impossible to make it more reliable. Close https://github.com/zalando/patroni/issues/2779
This commit is contained in:
@@ -375,6 +375,12 @@ class TestHa(PostgresInit):
|
||||
def test_acquire_lock_as_primary(self):
|
||||
self.assertEqual(self.ha.run_cycle(), 'acquired session lock as a leader')
|
||||
|
||||
def test_leader_race_stale_primary(self):
|
||||
with patch.object(Postgresql, 'get_primary_timeline', Mock(return_value=1)), \
|
||||
patch('patroni.ha.logger.warning') as mock_logger:
|
||||
self.assertEqual(self.ha.run_cycle(), 'demoting self because i am not the healthiest node')
|
||||
self.assertEqual(mock_logger.call_args[0][0], 'My timeline %s is behind last known cluster timeline %s')
|
||||
|
||||
def test_promoted_by_acquiring_lock(self):
|
||||
self.ha.is_healthiest_node = true
|
||||
self.p.is_leader = false
|
||||
|
||||
Reference in New Issue
Block a user