Cache DCS instances to avoid thread leak in patronictl list -W (#3205)

Close #3202
This commit is contained in:
Alexander Kukushkin
2024-11-11 13:59:27 +01:00
committed by GitHub
parent 177101a1cc
commit e1faa38e90
2 changed files with 9 additions and 2 deletions
+7
View File
@@ -332,6 +332,10 @@ def is_citus_cluster() -> bool:
return click.get_current_context().obj['__mpp'].is_enabled()
# Cache DCS instances for given scope and group
__dcs_cache: Dict[Tuple[str, Optional[int]], AbstractDCS] = {}
def get_dcs(scope: str, group: Optional[int]) -> AbstractDCS:
"""Get the DCS object.
@@ -345,6 +349,8 @@ def get_dcs(scope: str, group: Optional[int]) -> AbstractDCS:
:raises:
:class:`PatroniCtlException`: if not suitable DCS configuration could be found.
"""
if (scope, group) in __dcs_cache:
return __dcs_cache[(scope, group)]
config = _get_configuration()
config.update({'scope': scope, 'patronictl': True})
if group is not None:
@@ -355,6 +361,7 @@ def get_dcs(scope: str, group: Optional[int]) -> AbstractDCS:
if is_citus_cluster() and group is None:
dcs.is_mpp_coordinator = lambda: True
click.get_current_context().obj['__mpp'] = dcs.mpp
__dcs_cache[(scope, group)] = dcs
return dcs
except PatroniException as e:
raise PatroniCtlException(str(e))
+2 -2
View File
@@ -249,8 +249,8 @@ class TestCtl(unittest.TestCase):
@patch('patroni.dynamic_loader.iter_modules', Mock(return_value=['patroni.dcs.dummy', 'patroni.dcs.etcd']))
def test_get_dcs(self):
with click.Context(click.Command('list')) as ctx:
ctx.obj = {'__config': {'dummy': {}}, '__mpp': get_mpp({})}
self.assertRaises(PatroniCtlException, get_dcs, 'dummy', 0)
ctx.obj = {'__config': {'dummy2': {}}, '__mpp': get_mpp({})}
self.assertRaises(PatroniCtlException, get_dcs, 'dummy2', 0)
@patch('patroni.psycopg.connect', psycopg_connect)
@patch('patroni.ctl.query_member', Mock(return_value=([['mock column']], None)))