Skip to content

Fixing sentinel command execution to allow returning of actual responses when meaningful - behaviour controlled by 'return_responses' argument. #3191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Jun 5, 2025
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2746dcd
Fixing sentinel command response
mahigupta Mar 23, 2024
c2d207b
Linter check pass
mahigupta Mar 23, 2024
bdc0a5f
Merge branch 'master' into issue/3139
mahigupta Mar 28, 2024
596458f
Merge branch 'master' into issue/3139
mahigupta May 6, 2024
87484ad
Merge branch 'master' into issue/3139
mahigupta May 8, 2024
659da06
Merge branch 'master' into issue/3139
mahigupta May 10, 2024
0b67b59
Merge branch 'master' into issue/3139
mahigupta May 16, 2024
e31cb83
Merge branch 'master' into issue/3139
mahigupta May 21, 2024
09e6ea3
Merge branch 'master' into issue/3139
mahigupta May 26, 2024
0dcc41a
Merge branch 'master' into issue/3139
mahigupta Jun 1, 2024
8fab22d
Merge branch 'master' into issue/3139
mahigupta Aug 9, 2024
de33f88
Merge branch 'master' into issue/3139
mahigupta Aug 11, 2024
3f92109
Merge branch 'master' into issue/3139
mahigupta Sep 17, 2024
f2ffe1d
Merge branch 'master' into issue/3139
petyaslavova May 14, 2025
1ef7f34
Applying review comments and fixing some issues.
petyaslavova May 15, 2025
5d7fd79
Fix several spelling mistakes
petyaslavova May 15, 2025
89aba81
Adding new sentinel integration tests. Fixing the boolean return valu…
petyaslavova May 16, 2025
638b8fe
Merge branch 'master' into issue/3139
petyaslavova May 27, 2025
e322a69
Merge branch 'master' into issue/3139
petyaslavova May 28, 2025
3110e57
Merge branch 'master' into issue/3139
petyaslavova Jun 2, 2025
d4ddc17
Replacing usage of reduce in the boolean return types with python's b…
petyaslavova Jun 5, 2025
4c88b66
Changing the default behavior to be as before, returning of the respo…
petyaslavova Jun 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
* Fixed sentinel execute command response
* Move doctests (doc code examples) to main branch
* Update `ResponseT` type hint
* Allow to control the minimum SSL version
Expand Down
26 changes: 18 additions & 8 deletions redis/asyncio/sentinel.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import asyncio
import random
import weakref
from functools import reduce
from typing import AsyncIterator, Iterable, Mapping, Optional, Sequence, Tuple, Type

from redis.asyncio.client import Redis
Expand Down Expand Up @@ -230,15 +231,24 @@ async def execute_command(self, *args, **kwargs):
if "once" in kwargs.keys():
kwargs.pop("once")

# Check if command suppose to return boolean response.
bool_resp = bool(kwargs.get("bool_resp", False))
if "bool_resp" in kwargs.keys():
kwargs.pop("bool_resp")

if once:
await random.choice(self.sentinels).execute_command(*args, **kwargs)
else:
tasks = [
asyncio.Task(sentinel.execute_command(*args, **kwargs))
for sentinel in self.sentinels
]
await asyncio.gather(*tasks)
return True
return await random.choice(self.sentinels).execute_command(*args, **kwargs)

tasks = [
asyncio.Task(sentinel.execute_command(*args, **kwargs))
for sentinel in self.sentinels
]
responses = await asyncio.gather(*tasks)

if bool_resp:
return reduce(lambda x, y: x and y, responses)

return responses

def __repr__(self):
sentinel_addresses = []
Expand Down
30 changes: 20 additions & 10 deletions redis/commands/sentinel.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,39 @@ def sentinel(self, *args):

def sentinel_get_master_addr_by_name(self, service_name):
"""Returns a (host, port) pair for the given ``service_name``"""
return self.execute_command("SENTINEL GET-MASTER-ADDR-BY-NAME", service_name)
return self.execute_command(
"SENTINEL GET-MASTER-ADDR-BY-NAME", service_name, once=True
)

def sentinel_master(self, service_name):
"""Returns a dictionary containing the specified masters state."""
return self.execute_command("SENTINEL MASTER", service_name)

def sentinel_masters(self):
"""Returns a list of dictionaries containing each master's state."""
return self.execute_command("SENTINEL MASTERS")
return self.execute_command("SENTINEL MASTERS", once=True)

def sentinel_monitor(self, name, ip, port, quorum):
"""Add a new master to Sentinel to be monitored"""
return self.execute_command("SENTINEL MONITOR", name, ip, port, quorum)
return self.execute_command(
"SENTINEL MONITOR", name, ip, port, quorum, bool_resp=True
)

def sentinel_remove(self, name):
"""Remove a master from Sentinel's monitoring"""
return self.execute_command("SENTINEL REMOVE", name)
return self.execute_command("SENTINEL REMOVE", name, bool_resp=True)

def sentinel_sentinels(self, service_name):
"""Returns a list of sentinels for ``service_name``"""
return self.execute_command("SENTINEL SENTINELS", service_name)

def sentinel_set(self, name, option, value):
"""Set Sentinel monitoring parameters for a given master"""
return self.execute_command("SENTINEL SET", name, option, value)
return self.execute_command("SENTINEL SET", name, option, value, bool_resp=True)

def sentinel_slaves(self, service_name):
"""Returns a list of slaves for ``service_name``"""
return self.execute_command("SENTINEL SLAVES", service_name)
return self.execute_command("SENTINEL SLAVES", service_name, once=True)

def sentinel_reset(self, pattern):
"""
Expand All @@ -52,7 +56,9 @@ def sentinel_reset(self, pattern):
failover in progress), and removes every slave and sentinel already
discovered and associated with the master.
"""
return self.execute_command("SENTINEL RESET", pattern, once=True)
return self.execute_command(
"SENTINEL RESET", pattern, once=True, bool_resp=True
)

def sentinel_failover(self, new_master_name):
"""
Expand All @@ -61,7 +67,9 @@ def sentinel_failover(self, new_master_name):
configuration will be published so that the other Sentinels will
update their configurations).
"""
return self.execute_command("SENTINEL FAILOVER", new_master_name)
return self.execute_command(
"SENTINEL FAILOVER", new_master_name, bool_resp=True
)

def sentinel_ckquorum(self, new_master_name):
"""
Expand All @@ -72,7 +80,9 @@ def sentinel_ckquorum(self, new_master_name):
This command should be used in monitoring systems to check if a
Sentinel deployment is ok.
"""
return self.execute_command("SENTINEL CKQUORUM", new_master_name, once=True)
return self.execute_command(
"SENTINEL CKQUORUM", new_master_name, once=True, bool_resp=True
)

def sentinel_flushconfig(self):
"""
Expand All @@ -90,7 +100,7 @@ def sentinel_flushconfig(self):
This command works even if the previous configuration file is
completely missing.
"""
return self.execute_command("SENTINEL FLUSHCONFIG")
return self.execute_command("SENTINEL FLUSHCONFIG", bool_resp=True)


class AsyncSentinelCommands(SentinelCommands):
Expand Down
21 changes: 16 additions & 5 deletions redis/sentinel.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import random
import weakref
from functools import reduce
from typing import Optional

from redis.client import Redis
Expand Down Expand Up @@ -257,12 +258,22 @@ def execute_command(self, *args, **kwargs):
if "once" in kwargs.keys():
kwargs.pop("once")

# Check if command suppose to return boolean response.
bool_resp = bool(kwargs.get("bool_resp", False))
if "bool_resp" in kwargs.keys():
kwargs.pop("bool_resp")

if once:
random.choice(self.sentinels).execute_command(*args, **kwargs)
else:
for sentinel in self.sentinels:
sentinel.execute_command(*args, **kwargs)
return True
return random.choice(self.sentinels).execute_command(*args, **kwargs)

responses = []
for sentinel in self.sentinels:
responses.append(sentinel.execute_command(*args, **kwargs))

if bool_resp:
return reduce(lambda x, y: x and y, responses)

return responses

def __repr__(self):
sentinel_addresses = []
Expand Down
Loading