Skip to content

Commit b705514

Browse files
majiayu000claude
andcommitted
Add REPLICA aliases for deprecated SLAVE terminology in Sentinel (#3817)
Redis 5.0 deprecated SLAVE in favor of REPLICA. This adds aliases for the Sentinel APIs to match the modern Redis terminology: - ReplicaNotFoundError (alias for SlaveNotFoundError) - Sentinel.replica_for() (alias for slave_for()) - Sentinel.discover_replicas() (alias for discover_slaves()) - Sentinel.filter_replicas() (alias for filter_slaves()) - SentinelConnectionPool.rotate_replicas() (alias for rotate_slaves()) Both sync and async implementations are updated. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 793af91 commit b705514

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

redis/asyncio/sentinel.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ class SlaveNotFoundError(ConnectionError):
2727
pass
2828

2929

30+
# Alias for REPLICA terminology (Redis 5.0+)
31+
ReplicaNotFoundError = SlaveNotFoundError
32+
33+
3034
class SentinelManagedConnection(Connection):
3135
def __init__(self, **kwargs):
3236
self.connection_pool = kwargs.pop("connection_pool")
@@ -166,6 +170,11 @@ async def rotate_slaves(self) -> AsyncIterator:
166170
pass
167171
raise SlaveNotFoundError(f"No slave found for {self.service_name!r}")
168172

173+
async def rotate_replicas(self) -> AsyncIterator:
174+
"""Round-robin replica balancer"""
175+
async for replica in self.rotate_slaves():
176+
yield replica
177+
169178

170179
class Sentinel(AsyncSentinelCommands):
171180
"""
@@ -318,6 +327,12 @@ def filter_slaves(
318327
slaves_alive.append((slave["ip"], slave["port"]))
319328
return slaves_alive
320329

330+
def filter_replicas(
331+
self, replicas: Iterable[Mapping]
332+
) -> Sequence[Tuple[EncodableT, EncodableT]]:
333+
"""Remove replicas that are in an ODOWN or SDOWN state"""
334+
return self.filter_slaves(replicas)
335+
321336
async def discover_slaves(
322337
self, service_name: str
323338
) -> Sequence[Tuple[EncodableT, EncodableT]]:
@@ -332,6 +347,12 @@ async def discover_slaves(
332347
return slaves
333348
return []
334349

350+
async def discover_replicas(
351+
self, service_name: str
352+
) -> Sequence[Tuple[EncodableT, EncodableT]]:
353+
"""Returns a list of alive replicas for service ``service_name``"""
354+
return await self.discover_slaves(service_name)
355+
335356
def master_for(
336357
self,
337358
service_name: str,
@@ -402,3 +423,34 @@ def slave_for(
402423
connection_pool = connection_pool_class(service_name, self, **connection_kwargs)
403424
# The Redis object "owns" the pool
404425
return redis_class.from_pool(connection_pool)
426+
427+
def replica_for(
428+
self,
429+
service_name: str,
430+
redis_class: Type[Redis] = Redis,
431+
connection_pool_class: Type[SentinelConnectionPool] = SentinelConnectionPool,
432+
**kwargs,
433+
):
434+
"""
435+
Returns redis client instance for the ``service_name`` replica(s).
436+
437+
A SentinelConnectionPool class is used to retrieve the replica's
438+
address before establishing a new connection.
439+
440+
By default clients will be a :py:class:`~redis.Redis` instance.
441+
Specify a different class to the ``redis_class`` argument if you
442+
desire something different.
443+
444+
The ``connection_pool_class`` specifies the connection pool to use.
445+
The SentinelConnectionPool will be used by default.
446+
447+
All other keyword arguments are merged with any connection_kwargs
448+
passed to this class and passed to the connection pool as keyword
449+
arguments to be used to initialize Redis connections.
450+
"""
451+
return self.slave_for(
452+
service_name,
453+
redis_class=redis_class,
454+
connection_pool_class=connection_pool_class,
455+
**kwargs,
456+
)

redis/sentinel.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ class SlaveNotFoundError(ConnectionError):
2121
pass
2222

2323

24+
# Alias for REPLICA terminology (Redis 5.0+)
25+
ReplicaNotFoundError = SlaveNotFoundError
26+
27+
2428
class SentinelManagedConnection(Connection):
2529
def __init__(self, **kwargs):
2630
self.connection_pool = kwargs.pop("connection_pool")
@@ -198,6 +202,10 @@ def rotate_slaves(self):
198202
"Round-robin slave balancer"
199203
return self.proxy.rotate_slaves()
200204

205+
def rotate_replicas(self):
206+
"Round-robin replica balancer"
207+
return self.rotate_slaves()
208+
201209

202210
class Sentinel(SentinelCommands):
203211
"""
@@ -343,6 +351,10 @@ def filter_slaves(self, slaves):
343351
slaves_alive.append((slave["ip"], slave["port"]))
344352
return slaves_alive
345353

354+
def filter_replicas(self, replicas):
355+
"Remove replicas that are in an ODOWN or SDOWN state"
356+
return self.filter_slaves(replicas)
357+
346358
def discover_slaves(self, service_name):
347359
"Returns a list of alive slaves for service ``service_name``"
348360
for sentinel in self.sentinels:
@@ -355,6 +367,10 @@ def discover_slaves(self, service_name):
355367
return slaves
356368
return []
357369

370+
def discover_replicas(self, service_name):
371+
"Returns a list of alive replicas for service ``service_name``"
372+
return self.discover_slaves(service_name)
373+
358374
def master_for(
359375
self,
360376
service_name,
@@ -423,3 +439,34 @@ def slave_for(
423439
return redis_class.from_pool(
424440
connection_pool_class(service_name, self, **connection_kwargs)
425441
)
442+
443+
def replica_for(
444+
self,
445+
service_name,
446+
redis_class=Redis,
447+
connection_pool_class=SentinelConnectionPool,
448+
**kwargs,
449+
):
450+
"""
451+
Returns redis client instance for the ``service_name`` replica(s).
452+
453+
A SentinelConnectionPool class is used to retrieve the replica's
454+
address before establishing a new connection.
455+
456+
By default clients will be a :py:class:`~redis.Redis` instance.
457+
Specify a different class to the ``redis_class`` argument if you
458+
desire something different.
459+
460+
The ``connection_pool_class`` specifies the connection pool to use.
461+
The SentinelConnectionPool will be used by default.
462+
463+
All other keyword arguments are merged with any connection_kwargs
464+
passed to this class and passed to the connection pool as keyword
465+
arguments to be used to initialize Redis connections.
466+
"""
467+
return self.slave_for(
468+
service_name,
469+
redis_class=redis_class,
470+
connection_pool_class=connection_pool_class,
471+
**kwargs,
472+
)

0 commit comments

Comments
 (0)