From a431f50378007efebdcfcf492ea2ba4194adcf9d Mon Sep 17 00:00:00 2001 From: Alexander Kukushkin Date: Fri, 24 Sep 2021 08:22:54 +0200 Subject: [PATCH] Check only sync nodes when assessing failover capabilities (#2065) When synchronous_mode is enabled we should check only synchronous nodes in is_failover_possible(). --- patroni/ha.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/patroni/ha.py b/patroni/ha.py index 83c289c5..793c5d4f 100644 --- a/patroni/ha.py +++ b/patroni/ha.py @@ -317,10 +317,7 @@ class Ha(object): if timeout == 0: # We are requested to prefer failing over to restarting master. But see first if there # is anyone to fail over to. - members = self.cluster.members - if self.is_synchronous_mode(): - members = [m for m in members if self.cluster.sync.matches(m.name)] - if self.is_failover_possible(members): + if self.is_failover_possible(self.cluster.members, True): logger.info("Master crashed. Failing over.") self.demote('immediate') return 'stopped PostgreSQL to fail over after a crash' @@ -690,10 +687,12 @@ class Ha(object): logger.info('Ignoring the former leader being ahead of us') return True - def is_failover_possible(self, members): + def is_failover_possible(self, members, check_synchronous=True): ret = False cluster_timeline = self.cluster.timeline members = [m for m in members if m.name != self.state_handler.name and not m.nofailover and m.api_url] + if check_synchronous and self.is_synchronous_mode(): + members = [m for m in members if self.cluster.sync.matches(m.name)] if members: for st in self.fetch_nodes_statuses(members): not_allowed_reason = st.failover_limitation() @@ -1180,7 +1179,7 @@ class Ha(object): if self.has_lock() and self.update_lock(): if self._async_executor.scheduled_action == 'doing crash recovery in a single user mode': time_left = self.patroni.config['master_start_timeout'] - (time.time() - self._crash_recovery_started) - if time_left <= 0 and self.is_failover_possible(self.cluster.members): + if time_left <= 0 and self.is_failover_possible(self.cluster.members, True): logger.info("Demoting self because crash recovery is taking too long") self.state_handler.cancellable.cancel(True) self.demote('immediate') @@ -1287,7 +1286,7 @@ class Ha(object): time_left = timeout - self.state_handler.time_in_state() if time_left <= 0: - if self.is_failover_possible(self.cluster.members): + if self.is_failover_possible(self.cluster.members, True): logger.info("Demoting self because master startup is taking too long") self.demote('immediate') return 'stopped PostgreSQL because of startup timeout'