Skip to content

Commit faf55b6

Browse files
authored
Add support for CLUSTER SHARDS (#2151)
* Add support for CLUSTER SHARDS * linters * add docstring * linters
1 parent 3a88022 commit faf55b6

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

redis/cluster.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,26 @@ def fix_server(*args):
9292
return slots
9393

9494

95+
def parse_cluster_shards(resp, **options):
96+
"""
97+
Parse CLUSTER SHARDS response.
98+
"""
99+
shards = []
100+
for x in resp:
101+
shard = {"slots": [], "nodes": []}
102+
for i in range(0, len(x[1]), 2):
103+
shard["slots"].append((x[1][i], (x[1][i + 1])))
104+
nodes = x[3]
105+
for node in nodes:
106+
dict_node = {}
107+
for i in range(0, len(node), 2):
108+
dict_node[node[i]] = node[i + 1]
109+
shard["nodes"].append(dict_node)
110+
shards.append(shard)
111+
112+
return shards
113+
114+
95115
PRIMARY = "primary"
96116
REPLICA = "replica"
97117
SLOT_ID = "slot-id"
@@ -274,6 +294,7 @@ class AbstractRedisCluster:
274294
"CLUSTER RESET",
275295
"CLUSTER SET-CONFIG-EPOCH",
276296
"CLUSTER SLOTS",
297+
"CLUSTER SHARDS",
277298
"CLUSTER COUNT-FAILURE-REPORTS",
278299
"CLUSTER KEYSLOT",
279300
"COMMAND",
@@ -354,7 +375,10 @@ class AbstractRedisCluster:
354375
],
355376
)
356377

357-
CLUSTER_COMMANDS_RESPONSE_CALLBACKS = {"CLUSTER SLOTS": parse_cluster_slots}
378+
CLUSTER_COMMANDS_RESPONSE_CALLBACKS = {
379+
"CLUSTER SLOTS": parse_cluster_slots,
380+
"CLUSTER SHARDS": parse_cluster_shards,
381+
}
358382

359383
RESULT_CALLBACKS = dict_merge(
360384
list_keys_to_dict(["PUBSUB NUMSUB"], parse_pubsub_numsub),

redis/commands/cluster.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,14 @@ def cluster_slots(self, target_nodes: Optional["TargetNodesT"] = None) -> Respon
581581
"""
582582
return self.execute_command("CLUSTER SLOTS", target_nodes=target_nodes)
583583

584+
def cluster_shards(self, target_nodes=None):
585+
"""
586+
Returns details about the shards of the cluster.
587+
588+
For more information see https://redis.io/commands/cluster-shards
589+
"""
590+
return self.execute_command("CLUSTER SHARDS", target_nodes=target_nodes)
591+
584592
def cluster_links(self, target_node: "TargetNodesT") -> ResponseT:
585593
"""
586594
Each node in a Redis Cluster maintains a pair of long-lived TCP link with each

tests/test_cluster.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,29 @@ def test_cluster_slots(self, r):
856856
assert cluster_slots.get((0, 8191)) is not None
857857
assert cluster_slots.get((0, 8191)).get("primary") == ("127.0.0.1", 7000)
858858

859+
@skip_if_server_version_lt("7.0.0")
860+
@skip_if_redis_enterprise()
861+
def test_cluster_shards(self, r):
862+
cluster_shards = r.cluster_shards()
863+
assert isinstance(cluster_shards, list)
864+
assert isinstance(cluster_shards[0], dict)
865+
attributes = [
866+
"id",
867+
"endpoint",
868+
"ip",
869+
"hostname",
870+
"port",
871+
"tls-port",
872+
"role",
873+
"replication-offset",
874+
"health",
875+
]
876+
for x in cluster_shards:
877+
assert list(x.keys()) == ["slots", "nodes"]
878+
for node in x["nodes"]:
879+
for attribute in node.keys():
880+
assert attribute in attributes
881+
859882
@skip_if_redis_enterprise()
860883
def test_cluster_addslots(self, r):
861884
node = r.get_random_node()

0 commit comments

Comments
 (0)