Skip to content

Commit 333eb3b

Browse files
author
András Váczi
committed
Add typing #2
1 parent f0ac10e commit 333eb3b

File tree

2 files changed

+38
-30
lines changed

2 files changed

+38
-30
lines changed

patroni/ha.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ def acquire_lock(self) -> bool:
361361
multisite_ret = self.patroni.multisite.resolve_leader()
362362
if multisite_ret:
363363
logger.error("Releasing leader lock because multi site status is: %s", multisite_ret)
364-
self.dcs.delete_leader()
364+
self.dcs.delete_leader(None, None)
365365
return False
366366
return ret
367367

@@ -1599,6 +1599,7 @@ def before_shutdown() -> None:
15991599
with self._async_executor:
16001600
self.release_leader_key_voluntarily(checkpoint_location)
16011601
time.sleep(2) # Give a time to somebody to take the leader lock
1602+
# FIXME: multisite.on_shutdown() was already called above with _state_handler.stop(), do we really need it here?
16021603
if mode == 'multisite':
16031604
self.patroni.multisite.on_shutdown(self.state_handler.latest_checkpoint_location())
16041605
if mode_control['offline']:

patroni/multisite.py

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
import logging
44
import time
55

6-
from datetime import datetime
6+
from collections.abc import Callable
7+
from datetime import datetime, UTC
78
from threading import Event, Thread
8-
from typing import List, Optional
9+
from typing import Any, Dict, List, Optional, TYPE_CHECKING
910

1011
import six
1112

@@ -15,6 +16,10 @@
1516
from .dcs.kubernetes import catch_kubernetes_errors
1617
from .exceptions import DCSError
1718

19+
if TYPE_CHECKING: # pragma: no cover
20+
from .config import Config
21+
from .dcs import Cluster
22+
1823
logger = logging.getLogger(__name__)
1924

2025

@@ -24,19 +29,20 @@ class AbstractSiteController(object):
2429
is_active = False
2530

2631
dcs: AbstractDCS
32+
_has_leader: bool
2733

2834
def start(self):
2935
pass
3036

3137
def shutdown(self):
3238
pass
3339

34-
def get_active_standby_config(self) -> Optional[dict]:
40+
def get_active_standby_config(self) -> Dict[str, Any]:
3541
"""Returns currently active configuration for standby leader"""
3642
return {}
3743

38-
def is_leader_site(self):
39-
return self.get_active_standby_config() is None
44+
def is_leader_site(self) -> bool:
45+
return self.get_active_standby_config() == {}
4046

4147
def resolve_leader(self) -> Optional[str]:
4248
"""Try to become leader, update active config correspondingly.
@@ -54,13 +60,13 @@ def heartbeat(self):
5460
def release(self):
5561
pass
5662

57-
def status(self) -> dict:
63+
def status(self) -> Dict[str, Any]:
5864
return {}
5965

6066
def should_failover(self) -> bool:
6167
return False
6268

63-
def on_shutdown(self, checkpoint_location):
69+
def on_shutdown(self, checkpoint_location: int, prev_location: int):
6470
pass
6571

6672
def append_metrics(self, metrics: List[str], labels: str) -> None:
@@ -76,7 +82,7 @@ def status(self):
7682
class MultisiteController(Thread, AbstractSiteController):
7783
is_active = True
7884

79-
def __init__(self, config, on_change=None):
85+
def __init__(self, config: 'Config', on_change: Callable[[], None]):
8086
super().__init__()
8187
self.stop_requested = False
8288
self.on_change = on_change
@@ -116,21 +122,21 @@ def __init__(self, config, on_change=None):
116122
self.switchover_timeout = msconfig.get('switchover_timeout', 300)
117123

118124
self._heartbeat = Event()
119-
self._standby_config = None
125+
self._standby_config = {}
120126
self._leader_resolved = Event()
121127
self._has_leader = False
122128
self._release = False
123129
self._status = None
124130
self._failover_target = None
125-
self._failover_timeout = None
131+
self._failover_timeout = 0
126132

127133
self.site_switches = None
128134

129135
self._dcs_error = None
130136

131137
def status(self):
132138
return {
133-
"status": "Leader" if self._has_leader or self._standby_config is None else "Standby",
139+
"status": "Leader" if self._has_leader or self._standby_config == {} else "Standby",
134140
"active": True,
135141
"name": self.name,
136142
"standby_config": self.get_active_standby_config(),
@@ -167,7 +173,7 @@ def release(self):
167173
def should_failover(self):
168174
return self._failover_target is not None and self._failover_target != self.name
169175

170-
def on_shutdown(self, checkpoint_location):
176+
def on_shutdown(self, checkpoint_location: int, prev_location: int):
171177
""" Called when shutdown for multisite failover has completed.
172178
"""
173179
# TODO: check if we replicated everything to standby site
@@ -193,12 +199,11 @@ def _set_standby_config(self, other: Member):
193199
logger.info(f"Setting standby configuration to: {self._standby_config}")
194200
return old_conf != self._standby_config
195201

196-
def _check_transition(self, leader, note=None):
202+
def _check_transition(self, leader: bool, note: str):
197203
if self._has_leader != leader:
198204
logger.info("Multisite state transition")
199205
self._has_leader = leader
200-
if self.on_change:
201-
self.on_change()
206+
self.on_change()
202207
if self._state_updater and self._status != leader:
203208
self._state_updater.state_transition('Leader' if leader else 'Standby', note)
204209
self._status = leader
@@ -225,7 +230,7 @@ def _resolve_multisite_leader(self):
225230
# Became leader of unlocked cluster
226231
if self.dcs.attempt_to_acquire_leader():
227232
logger.info("Became multisite leader")
228-
self._standby_config = None
233+
self._standby_config = {}
229234
self._check_transition(leader=True, note="Acquired multisite leader status")
230235
if cluster.failover and cluster.failover.target_site and cluster.failover.target_site == self.name:
231236
logger.info("Cleaning up multisite failover key after acquiring leader status")
@@ -256,7 +261,7 @@ def _resolve_multisite_leader(self):
256261
if self.dcs.update_leader(cluster, None):
257262
logger.info("Updated multisite leader lease")
258263
# Make sure we are disabled from standby mode
259-
self._standby_config = None
264+
self._standby_config = {}
260265
self._check_transition(leader=True, note="Already have multisite leader status")
261266
self._check_for_failover(cluster)
262267
else:
@@ -270,8 +275,8 @@ def _resolve_multisite_leader(self):
270275
# Failover successful or someone else took over
271276
if self._failover_target is not None:
272277
self._failover_target = None
273-
self._failover_timeout = None
274-
if self._set_standby_config(cluster.leader.member):
278+
self._failover_timeout = 0
279+
if cluster.leader and self._set_standby_config(cluster.leader.member):
275280
# Wake up anyway to notice that we need to replicate from new leader. For the other case
276281
# _check_transition() handles the wake.
277282
if not self._has_leader:
@@ -313,15 +318,15 @@ def _observe_leader(self):
313318
# The leader is us
314319
if lock_owner == self.name:
315320
logger.info("Multisite leader is us")
316-
self._standby_config = None
321+
self._standby_config = {}
317322
else:
318323
logger.info(f"Multisite leader is {lock_owner}")
319-
self._set_standby_config(cluster.leader.member)
324+
self._set_standby_config(cluster.leader.member) # pyright: ignore
320325
except DCSError as e:
321326
# On replicas we need to know the multisite status only for rewinding.
322327
logger.warning(f"Error accessing multisite DCS: {e}")
323328

324-
def _update_history(self, cluster):
329+
def _update_history(self, cluster: 'Cluster'):
325330
if cluster.history and cluster.history.lines and isinstance(cluster.history.lines[0], dict):
326331
self.site_switches = cluster.history.lines[0].get('switches')
327332

@@ -349,7 +354,7 @@ def _check_for_failover(self, cluster: Cluster):
349354
self._failover_target = cluster.failover.target_site
350355
else:
351356
self._failover_target = None
352-
self._failover_timeout = None
357+
self._failover_timeout = 0
353358

354359
def touch_member(self):
355360
data = {
@@ -379,14 +384,14 @@ def shutdown(self):
379384
self._heartbeat.set()
380385
self.join()
381386

382-
def append_metrics(self, metrics, labels):
387+
def append_metrics(self, metrics: List[str], labels: str):
383388
metrics.append("# HELP patroni_multisite_switches Number of times multisite leader has been switched")
384389
metrics.append("# TYPE patroni_multisite_switches counter")
385390
metrics.append("patroni_multisite_switches{0} {1}".format(labels, self.site_switches))
386391

387392

388393
class KubernetesStateManagement:
389-
def __init__(self, crd_name, crd_uid, reporter, crd_api):
394+
def __init__(self, crd_name: str, crd_uid: str, reporter: str, crd_api: str):
390395
self.crd_namespace, self.crd_name = (['default'] + crd_name.rsplit('.', 1))[-2:]
391396
self.crd_uid = crd_uid
392397
self.reporter = reporter
@@ -402,13 +407,15 @@ def __init__(self, crd_name, crd_uid, reporter, crd_api):
402407
self._status_update = None
403408
self._event_obj = None
404409

405-
def state_transition(self, new_state, note):
410+
def state_transition(self, new_state: str, note: str):
406411
self._status_update = {"status": {"Multisite": new_state}}
407412

408-
failover_time = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S.%fZ")
413+
failover_time = datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%S.%fZ")
409414
reason = 'Promote' if new_state == 'Leader' else 'Demote'
410-
if note is None:
411-
note = 'Acquired multisite leader' if new_state == 'Leader' else 'Became a standby cluster'
415+
416+
# TODO: check if this is needed, no current call comes without note (this is already reflected in the signature)
417+
# if note is None:
418+
# note = 'Acquired multisite leader' if new_state == 'Leader' else 'Became a standby cluster'
412419

413420
self._event_obj = kubernetes.client.EventsV1Event(
414421
action='Failover',

0 commit comments

Comments
 (0)