Skip to content
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

Fixing sentinel command response #3191

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES
@@ -1,3 +1,4 @@
* Fixed sentinel execute command response
* Allow to control the minimum SSL version
* Add an optional lock_name attribute to LockError.
* Fix return types for `get`, `set_path` and `strappend` in JSONCommands
Expand Down
26 changes: 18 additions & 8 deletions redis/asyncio/sentinel.py
@@ -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
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
@@ -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