coredis 5.5.0__cp313-cp313-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 22fe76227e35f92ab5c3__mypyc.cpython-313-darwin.so +0 -0
- coredis/__init__.py +42 -0
- coredis/_enum.py +42 -0
- coredis/_json.py +11 -0
- coredis/_packer.cpython-313-darwin.so +0 -0
- coredis/_packer.py +71 -0
- coredis/_protocols.py +50 -0
- coredis/_py_311_typing.py +20 -0
- coredis/_py_312_typing.py +17 -0
- coredis/_sidecar.py +114 -0
- coredis/_utils.cpython-313-darwin.so +0 -0
- coredis/_utils.py +440 -0
- coredis/_version.py +34 -0
- coredis/_version.pyi +1 -0
- coredis/cache.py +801 -0
- coredis/client/__init__.py +6 -0
- coredis/client/basic.py +1240 -0
- coredis/client/cluster.py +1265 -0
- coredis/commands/__init__.py +64 -0
- coredis/commands/_key_spec.py +517 -0
- coredis/commands/_utils.py +108 -0
- coredis/commands/_validators.py +159 -0
- coredis/commands/_wrappers.py +175 -0
- coredis/commands/bitfield.py +110 -0
- coredis/commands/constants.py +662 -0
- coredis/commands/core.py +8484 -0
- coredis/commands/function.py +408 -0
- coredis/commands/monitor.py +168 -0
- coredis/commands/pubsub.py +905 -0
- coredis/commands/request.py +108 -0
- coredis/commands/script.py +296 -0
- coredis/commands/sentinel.py +246 -0
- coredis/config.py +50 -0
- coredis/connection.py +906 -0
- coredis/constants.cpython-313-darwin.so +0 -0
- coredis/constants.py +37 -0
- coredis/credentials.py +45 -0
- coredis/exceptions.py +360 -0
- coredis/experimental/__init__.py +1 -0
- coredis/globals.py +23 -0
- coredis/modules/__init__.py +121 -0
- coredis/modules/autocomplete.py +138 -0
- coredis/modules/base.py +262 -0
- coredis/modules/filters.py +1319 -0
- coredis/modules/graph.py +362 -0
- coredis/modules/json.py +691 -0
- coredis/modules/response/__init__.py +0 -0
- coredis/modules/response/_callbacks/__init__.py +0 -0
- coredis/modules/response/_callbacks/autocomplete.py +42 -0
- coredis/modules/response/_callbacks/graph.py +237 -0
- coredis/modules/response/_callbacks/json.py +21 -0
- coredis/modules/response/_callbacks/search.py +221 -0
- coredis/modules/response/_callbacks/timeseries.py +158 -0
- coredis/modules/response/types.py +179 -0
- coredis/modules/search.py +1089 -0
- coredis/modules/timeseries.py +1139 -0
- coredis/parser.cpython-313-darwin.so +0 -0
- coredis/parser.py +344 -0
- coredis/pipeline.py +1225 -0
- coredis/pool/__init__.py +11 -0
- coredis/pool/basic.py +453 -0
- coredis/pool/cluster.py +517 -0
- coredis/pool/nodemanager.py +340 -0
- coredis/py.typed +0 -0
- coredis/recipes/__init__.py +0 -0
- coredis/recipes/credentials/__init__.py +5 -0
- coredis/recipes/credentials/iam_provider.py +63 -0
- coredis/recipes/locks/__init__.py +5 -0
- coredis/recipes/locks/extend.lua +17 -0
- coredis/recipes/locks/lua_lock.py +281 -0
- coredis/recipes/locks/release.lua +10 -0
- coredis/response/__init__.py +5 -0
- coredis/response/_callbacks/__init__.py +538 -0
- coredis/response/_callbacks/acl.py +32 -0
- coredis/response/_callbacks/cluster.py +183 -0
- coredis/response/_callbacks/command.py +86 -0
- coredis/response/_callbacks/connection.py +31 -0
- coredis/response/_callbacks/geo.py +58 -0
- coredis/response/_callbacks/hash.py +85 -0
- coredis/response/_callbacks/keys.py +59 -0
- coredis/response/_callbacks/module.py +33 -0
- coredis/response/_callbacks/script.py +85 -0
- coredis/response/_callbacks/sentinel.py +179 -0
- coredis/response/_callbacks/server.py +241 -0
- coredis/response/_callbacks/sets.py +44 -0
- coredis/response/_callbacks/sorted_set.py +204 -0
- coredis/response/_callbacks/streams.py +185 -0
- coredis/response/_callbacks/strings.py +70 -0
- coredis/response/_callbacks/vector_sets.py +159 -0
- coredis/response/_utils.py +33 -0
- coredis/response/types.py +416 -0
- coredis/retry.py +233 -0
- coredis/sentinel.py +477 -0
- coredis/stream.py +369 -0
- coredis/tokens.py +2286 -0
- coredis/typing.py +593 -0
- coredis-5.5.0.dist-info/METADATA +211 -0
- coredis-5.5.0.dist-info/RECORD +100 -0
- coredis-5.5.0.dist-info/WHEEL +6 -0
- coredis-5.5.0.dist-info/licenses/LICENSE +23 -0
coredis/sentinel.py
ADDED
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import random
|
|
4
|
+
import ssl
|
|
5
|
+
import weakref
|
|
6
|
+
from typing import Any, cast, overload
|
|
7
|
+
|
|
8
|
+
from coredis import Redis
|
|
9
|
+
from coredis._utils import nativestr
|
|
10
|
+
from coredis.cache import AbstractCache
|
|
11
|
+
from coredis.connection import Connection
|
|
12
|
+
from coredis.credentials import AbstractCredentialProvider
|
|
13
|
+
from coredis.exceptions import (
|
|
14
|
+
ConnectionError,
|
|
15
|
+
PrimaryNotFoundError,
|
|
16
|
+
ReplicaNotFoundError,
|
|
17
|
+
ResponseError,
|
|
18
|
+
TimeoutError,
|
|
19
|
+
)
|
|
20
|
+
from coredis.pool import ConnectionPool
|
|
21
|
+
from coredis.typing import (
|
|
22
|
+
AnyStr,
|
|
23
|
+
Generic,
|
|
24
|
+
Iterable,
|
|
25
|
+
Literal,
|
|
26
|
+
ResponsePrimitive,
|
|
27
|
+
StringT,
|
|
28
|
+
TypeAdapter,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class SentinelManagedConnection(Connection, Generic[AnyStr]):
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
connection_pool: SentinelConnectionPool,
|
|
36
|
+
host: str = "127.0.0.1",
|
|
37
|
+
port: int = 6379,
|
|
38
|
+
username: str | None = None,
|
|
39
|
+
password: str | None = None,
|
|
40
|
+
credential_provider: AbstractCredentialProvider | None = None,
|
|
41
|
+
db: int = 0,
|
|
42
|
+
stream_timeout: float | None = None,
|
|
43
|
+
connect_timeout: float | None = None,
|
|
44
|
+
ssl_context: ssl.SSLContext | None = None,
|
|
45
|
+
encoding: str = "utf-8",
|
|
46
|
+
decode_responses: bool = False,
|
|
47
|
+
socket_keepalive: bool | None = None,
|
|
48
|
+
socket_keepalive_options: dict[int, int | bytes] | None = None,
|
|
49
|
+
*,
|
|
50
|
+
client_name: str | None = None,
|
|
51
|
+
protocol_version: Literal[2, 3] = 3,
|
|
52
|
+
):
|
|
53
|
+
self.connection_pool: SentinelConnectionPool = weakref.proxy(connection_pool)
|
|
54
|
+
super().__init__(
|
|
55
|
+
host=host,
|
|
56
|
+
port=port,
|
|
57
|
+
username=username,
|
|
58
|
+
password=password,
|
|
59
|
+
credential_provider=credential_provider,
|
|
60
|
+
db=db,
|
|
61
|
+
stream_timeout=stream_timeout,
|
|
62
|
+
connect_timeout=connect_timeout,
|
|
63
|
+
ssl_context=ssl_context,
|
|
64
|
+
encoding=encoding,
|
|
65
|
+
decode_responses=decode_responses,
|
|
66
|
+
socket_keepalive=socket_keepalive,
|
|
67
|
+
socket_keepalive_options=socket_keepalive_options,
|
|
68
|
+
client_name=client_name,
|
|
69
|
+
protocol_version=protocol_version,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def __repr__(self) -> str:
|
|
73
|
+
pool = self.connection_pool
|
|
74
|
+
|
|
75
|
+
if self.host:
|
|
76
|
+
host_info = f",host={self.host},port={self.port}"
|
|
77
|
+
else:
|
|
78
|
+
host_info = ""
|
|
79
|
+
s = f"{type(self).__name__}<service={pool.service_name}{host_info}>"
|
|
80
|
+
|
|
81
|
+
return s
|
|
82
|
+
|
|
83
|
+
async def connect_to(self, address: tuple[str, int]) -> None:
|
|
84
|
+
self.host, self.port = address
|
|
85
|
+
await super().connect()
|
|
86
|
+
|
|
87
|
+
async def connect(self) -> None:
|
|
88
|
+
if not self.is_connected:
|
|
89
|
+
if self.connection_pool.is_primary:
|
|
90
|
+
await self.connect_to(await self.connection_pool.get_primary_address())
|
|
91
|
+
else:
|
|
92
|
+
for replica in await self.connection_pool.rotate_replicas():
|
|
93
|
+
try:
|
|
94
|
+
return await self.connect_to(replica)
|
|
95
|
+
except ConnectionError:
|
|
96
|
+
continue
|
|
97
|
+
raise ReplicaNotFoundError # Never be here
|
|
98
|
+
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class SentinelConnectionPool(ConnectionPool):
|
|
103
|
+
"""
|
|
104
|
+
Sentinel backed connection pool.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
primary_address: tuple[str, int] | None
|
|
108
|
+
replica_counter: int | None
|
|
109
|
+
|
|
110
|
+
def __init__(
|
|
111
|
+
self,
|
|
112
|
+
service_name: StringT,
|
|
113
|
+
sentinel_manager: Sentinel[Any],
|
|
114
|
+
is_primary: bool = True,
|
|
115
|
+
check_connection: bool = True,
|
|
116
|
+
**kwargs: Any,
|
|
117
|
+
):
|
|
118
|
+
self.is_primary = is_primary
|
|
119
|
+
kwargs["connection_class"] = cast(
|
|
120
|
+
type[Connection],
|
|
121
|
+
kwargs.get(
|
|
122
|
+
"connection_class",
|
|
123
|
+
SentinelManagedConnection[AnyStr], # type: ignore
|
|
124
|
+
),
|
|
125
|
+
)
|
|
126
|
+
super().__init__(**kwargs)
|
|
127
|
+
self.connection_kwargs["connection_pool"] = self
|
|
128
|
+
self.service_name = nativestr(service_name)
|
|
129
|
+
self.sentinel_manager = sentinel_manager
|
|
130
|
+
self.check_connection = check_connection
|
|
131
|
+
|
|
132
|
+
def __repr__(self) -> str:
|
|
133
|
+
return (
|
|
134
|
+
f"{type(self).__name__}"
|
|
135
|
+
f"<service={self.service_name}"
|
|
136
|
+
f"({'primary' if self.is_primary else 'replica'})"
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
def reset(self) -> None:
|
|
140
|
+
super().reset()
|
|
141
|
+
self.primary_address = None
|
|
142
|
+
self.replica_counter = None
|
|
143
|
+
|
|
144
|
+
async def get_primary_address(self) -> tuple[str, int]:
|
|
145
|
+
primary_address = await self.sentinel_manager.discover_primary(self.service_name)
|
|
146
|
+
|
|
147
|
+
if self.is_primary:
|
|
148
|
+
if self.primary_address is None:
|
|
149
|
+
self.primary_address = primary_address
|
|
150
|
+
elif primary_address != self.primary_address:
|
|
151
|
+
# Primary address changed, disconnect all clients in this pool
|
|
152
|
+
self.disconnect()
|
|
153
|
+
|
|
154
|
+
return primary_address
|
|
155
|
+
|
|
156
|
+
async def rotate_replicas(self) -> list[tuple[str, int]]:
|
|
157
|
+
"""Round-robin replicas balancer"""
|
|
158
|
+
replicas = await self.sentinel_manager.discover_replicas(self.service_name)
|
|
159
|
+
replica_addresses: list[tuple[str, int]] = []
|
|
160
|
+
|
|
161
|
+
if replicas:
|
|
162
|
+
if self.replica_counter is None:
|
|
163
|
+
self.replica_counter = random.randint(0, len(replicas) - 1)
|
|
164
|
+
|
|
165
|
+
for _ in range(len(replicas)):
|
|
166
|
+
self.replica_counter = (self.replica_counter + 1) % len(replicas)
|
|
167
|
+
replica_addresses.append(replicas[self.replica_counter])
|
|
168
|
+
|
|
169
|
+
return replica_addresses
|
|
170
|
+
# Fallback to primary
|
|
171
|
+
try:
|
|
172
|
+
return [await self.get_primary_address()]
|
|
173
|
+
except PrimaryNotFoundError:
|
|
174
|
+
pass
|
|
175
|
+
raise ReplicaNotFoundError(f"No replica found for {self.service_name!r}")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class Sentinel(Generic[AnyStr]):
|
|
179
|
+
"""
|
|
180
|
+
Example use::
|
|
181
|
+
|
|
182
|
+
from coredis.sentinel import Sentinel
|
|
183
|
+
sentinel = Sentinel([('localhost', 26379)], stream_timeout=0.1)
|
|
184
|
+
async def test():
|
|
185
|
+
primary = await sentinel.primary_for('my-instance', stream_timeout=0.1)
|
|
186
|
+
await primary.set('foo', 'bar')
|
|
187
|
+
replica = await sentinel.replica_for('my-instance', stream_timeout=0.1)
|
|
188
|
+
await replica.get('foo')
|
|
189
|
+
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
@overload
|
|
193
|
+
def __init__(
|
|
194
|
+
self: Sentinel[bytes],
|
|
195
|
+
sentinels: Iterable[tuple[str, int]],
|
|
196
|
+
min_other_sentinels: int = ...,
|
|
197
|
+
sentinel_kwargs: dict[str, Any] | None = ...,
|
|
198
|
+
decode_responses: Literal[False] = ...,
|
|
199
|
+
cache: AbstractCache | None = None,
|
|
200
|
+
type_adapter: TypeAdapter | None = ...,
|
|
201
|
+
**connection_kwargs: Any,
|
|
202
|
+
) -> None: ...
|
|
203
|
+
|
|
204
|
+
@overload
|
|
205
|
+
def __init__(
|
|
206
|
+
self: Sentinel[str],
|
|
207
|
+
sentinels: Iterable[tuple[str, int]],
|
|
208
|
+
min_other_sentinels: int = ...,
|
|
209
|
+
sentinel_kwargs: dict[str, Any] | None = ...,
|
|
210
|
+
decode_responses: Literal[True] = ...,
|
|
211
|
+
cache: AbstractCache | None = None,
|
|
212
|
+
type_adapter: TypeAdapter | None = None,
|
|
213
|
+
**connection_kwargs: Any,
|
|
214
|
+
) -> None: ...
|
|
215
|
+
|
|
216
|
+
def __init__(
|
|
217
|
+
self,
|
|
218
|
+
sentinels: Iterable[tuple[str, int]],
|
|
219
|
+
min_other_sentinels: int = 0,
|
|
220
|
+
sentinel_kwargs: dict[str, Any] | None = None,
|
|
221
|
+
decode_responses: bool = False,
|
|
222
|
+
cache: AbstractCache | None = None,
|
|
223
|
+
type_adapter: TypeAdapter | None = None,
|
|
224
|
+
**connection_kwargs: Any,
|
|
225
|
+
) -> None:
|
|
226
|
+
"""
|
|
227
|
+
Changes
|
|
228
|
+
- .. versionadded:: 3.10.0
|
|
229
|
+
Accept :paramref:`cache` parameter to be used with primaries
|
|
230
|
+
and replicas returned from the sentinel instance.
|
|
231
|
+
|
|
232
|
+
:param sentinels: is a list of sentinel nodes. Each node is represented by
|
|
233
|
+
a pair (hostname, port).
|
|
234
|
+
:param min_other_sentinels: defined a minimum number of peers for a sentinel.
|
|
235
|
+
When querying a sentinel, if it doesn't meet this threshold, responses
|
|
236
|
+
from that sentinel won't be considered valid.
|
|
237
|
+
:param sentinel_kwargs: is a dictionary of connection arguments used when
|
|
238
|
+
connecting to sentinel instances. Any argument that can be passed to
|
|
239
|
+
a normal Redis connection can be specified here. If :paramref:`sentinel_kwargs` is
|
|
240
|
+
not specified, ``stream_timeout``, ``socket_keepalive``, ``decode_responses``
|
|
241
|
+
and ``protocol_version`` options specified in :paramref:`connection_kwargs` will be used.
|
|
242
|
+
:param cache: If provided the cache will be shared between both primaries and replicas
|
|
243
|
+
returned by this sentinel.
|
|
244
|
+
:param type_adapter: The adapter to use for serializing / deserializing customs types
|
|
245
|
+
when interacting with redis commands. If provided this adapter will be used for both
|
|
246
|
+
primaries and replicas returned by this sentinel.
|
|
247
|
+
:param connection_kwargs: are keyword arguments that will be used when
|
|
248
|
+
establishing a connection to a Redis server (i.e. are passed on to the
|
|
249
|
+
constructor of :class:`Redis` for all primary and replicas).
|
|
250
|
+
"""
|
|
251
|
+
# if sentinel_kwargs isn't defined, use the socket_* options from
|
|
252
|
+
# connection_kwargs
|
|
253
|
+
|
|
254
|
+
if not sentinel_kwargs:
|
|
255
|
+
sentinel_kwargs = {
|
|
256
|
+
k: v
|
|
257
|
+
for k, v in iter(connection_kwargs.items())
|
|
258
|
+
if k
|
|
259
|
+
in {
|
|
260
|
+
"socket_timeout",
|
|
261
|
+
"socket_keepalive",
|
|
262
|
+
"encoding",
|
|
263
|
+
"protocol_version",
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
self.sentinel_kwargs = sentinel_kwargs
|
|
268
|
+
self.min_other_sentinels = min_other_sentinels
|
|
269
|
+
self.connection_kwargs = connection_kwargs
|
|
270
|
+
self.__cache = cache
|
|
271
|
+
self.__type_adapter = type_adapter
|
|
272
|
+
self.connection_kwargs["decode_responses"] = self.sentinel_kwargs["decode_responses"] = (
|
|
273
|
+
decode_responses
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
self.sentinels = [
|
|
277
|
+
Redis(hostname, port, **self.sentinel_kwargs) for hostname, port in sentinels
|
|
278
|
+
]
|
|
279
|
+
|
|
280
|
+
def __repr__(self) -> str:
|
|
281
|
+
sentinel_addresses: list[str] = []
|
|
282
|
+
|
|
283
|
+
for sentinel in self.sentinels:
|
|
284
|
+
sentinel_addresses.append(
|
|
285
|
+
"{}:{}".format(
|
|
286
|
+
sentinel.connection_pool.connection_kwargs["host"],
|
|
287
|
+
sentinel.connection_pool.connection_kwargs["port"],
|
|
288
|
+
)
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
return "{}<sentinels=[{}]>".format(type(self).__name__, ",".join(sentinel_addresses))
|
|
292
|
+
|
|
293
|
+
def __check_primary_state(
|
|
294
|
+
self,
|
|
295
|
+
state: dict[str, ResponsePrimitive],
|
|
296
|
+
) -> bool:
|
|
297
|
+
if not state["is_master"] or state["is_sdown"] or state["is_odown"]:
|
|
298
|
+
return False
|
|
299
|
+
|
|
300
|
+
if int(state["num-other-sentinels"] or 0) < self.min_other_sentinels:
|
|
301
|
+
return False
|
|
302
|
+
|
|
303
|
+
return True
|
|
304
|
+
|
|
305
|
+
def __filter_replicas(
|
|
306
|
+
self, replicas: Iterable[dict[str, ResponsePrimitive]]
|
|
307
|
+
) -> list[tuple[str, int]]:
|
|
308
|
+
"""Removes replicas that are in an ODOWN or SDOWN state"""
|
|
309
|
+
replicas_alive: list[tuple[str, int]] = []
|
|
310
|
+
|
|
311
|
+
for replica in replicas:
|
|
312
|
+
if replica["is_odown"] or replica["is_sdown"]:
|
|
313
|
+
continue
|
|
314
|
+
ip, port = replica["ip"], replica["port"]
|
|
315
|
+
assert ip and port
|
|
316
|
+
replicas_alive.append((nativestr(ip), int(port)))
|
|
317
|
+
|
|
318
|
+
return replicas_alive
|
|
319
|
+
|
|
320
|
+
async def discover_primary(self, service_name: str) -> tuple[str, int]:
|
|
321
|
+
"""
|
|
322
|
+
Asks sentinel servers for the Redis primary's address corresponding
|
|
323
|
+
to the service labeled :paramref:`service_name`.
|
|
324
|
+
|
|
325
|
+
:return: A pair (address, port) or raises :exc:`~coredis.exceptions.PrimaryNotFoundError`
|
|
326
|
+
if no primary is found.
|
|
327
|
+
"""
|
|
328
|
+
|
|
329
|
+
for sentinel_no, sentinel in enumerate(self.sentinels):
|
|
330
|
+
try:
|
|
331
|
+
primaries = await sentinel.sentinel_masters()
|
|
332
|
+
except (ConnectionError, TimeoutError):
|
|
333
|
+
continue
|
|
334
|
+
state = primaries.get(service_name)
|
|
335
|
+
|
|
336
|
+
if state and self.__check_primary_state(state):
|
|
337
|
+
# Put this sentinel at the top of the list
|
|
338
|
+
self.sentinels[0], self.sentinels[sentinel_no] = (
|
|
339
|
+
sentinel,
|
|
340
|
+
self.sentinels[0],
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
return nativestr(state["ip"]), int(state["port"] or -1)
|
|
344
|
+
raise PrimaryNotFoundError(f"No primary found for {service_name!r}")
|
|
345
|
+
|
|
346
|
+
async def discover_replicas(self, service_name: str) -> list[tuple[str, int]]:
|
|
347
|
+
"""Returns a list of alive replicas for service :paramref:`service_name`"""
|
|
348
|
+
|
|
349
|
+
for sentinel in self.sentinels:
|
|
350
|
+
try:
|
|
351
|
+
replicas = await sentinel.sentinel_replicas(service_name)
|
|
352
|
+
except (ConnectionError, ResponseError, TimeoutError):
|
|
353
|
+
continue
|
|
354
|
+
filtered_replicas = self.__filter_replicas(replicas)
|
|
355
|
+
|
|
356
|
+
if filtered_replicas:
|
|
357
|
+
return filtered_replicas
|
|
358
|
+
|
|
359
|
+
return []
|
|
360
|
+
|
|
361
|
+
@overload
|
|
362
|
+
def primary_for(
|
|
363
|
+
self: Sentinel[bytes],
|
|
364
|
+
service_name: str,
|
|
365
|
+
*,
|
|
366
|
+
redis_class: type[Redis[bytes]] = ...,
|
|
367
|
+
connection_pool_class: type[SentinelConnectionPool] = ...,
|
|
368
|
+
**kwargs: Any,
|
|
369
|
+
) -> Redis[bytes]: ...
|
|
370
|
+
|
|
371
|
+
@overload
|
|
372
|
+
def primary_for(
|
|
373
|
+
self: Sentinel[str],
|
|
374
|
+
service_name: str,
|
|
375
|
+
*,
|
|
376
|
+
redis_class: type[Redis[str]] = ...,
|
|
377
|
+
connection_pool_class: type[SentinelConnectionPool] = ...,
|
|
378
|
+
**kwargs: Any,
|
|
379
|
+
) -> Redis[str]: ...
|
|
380
|
+
|
|
381
|
+
def primary_for(
|
|
382
|
+
self,
|
|
383
|
+
service_name: str,
|
|
384
|
+
*,
|
|
385
|
+
redis_class: type[Redis[Any]] = Redis[Any],
|
|
386
|
+
connection_pool_class: type[SentinelConnectionPool] = SentinelConnectionPool,
|
|
387
|
+
**kwargs: Any,
|
|
388
|
+
) -> Redis[bytes] | Redis[str]:
|
|
389
|
+
"""
|
|
390
|
+
Returns a redis client instance for the :paramref:`service_name` primary.
|
|
391
|
+
|
|
392
|
+
A :class:`coredis.sentinel.SentinelConnectionPool` class is used to
|
|
393
|
+
retrive the primary's address before establishing a new connection.
|
|
394
|
+
|
|
395
|
+
NOTE: If the primary's address has changed, any cached connections to
|
|
396
|
+
the old primary are closed.
|
|
397
|
+
|
|
398
|
+
By default clients will be a :class:`~coredis.Redis` instances.
|
|
399
|
+
Specify a different class to the :paramref:`redis_class` argument if you desire
|
|
400
|
+
something different.
|
|
401
|
+
|
|
402
|
+
The :paramref:`connection_pool_class` specifies the connection pool to use.
|
|
403
|
+
The :class:`~coredis.sentinel.SentinelConnectionPool` will be used by default.
|
|
404
|
+
|
|
405
|
+
All other keyword arguments are merged with any :paramref:`Sentinel.connection_kwargs`
|
|
406
|
+
passed to this class and passed to the connection pool as keyword
|
|
407
|
+
arguments to be used to initialize Redis connections.
|
|
408
|
+
"""
|
|
409
|
+
kwargs["is_primary"] = True
|
|
410
|
+
connection_kwargs = dict(self.connection_kwargs)
|
|
411
|
+
connection_kwargs.update(kwargs)
|
|
412
|
+
|
|
413
|
+
return redis_class(
|
|
414
|
+
connection_pool=connection_pool_class(
|
|
415
|
+
service_name,
|
|
416
|
+
self,
|
|
417
|
+
**connection_kwargs,
|
|
418
|
+
),
|
|
419
|
+
cache=self.__cache,
|
|
420
|
+
type_adapter=self.__type_adapter,
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
@overload
|
|
424
|
+
def replica_for(
|
|
425
|
+
self: Sentinel[bytes],
|
|
426
|
+
service_name: str,
|
|
427
|
+
redis_class: type[Redis[bytes]] = ...,
|
|
428
|
+
connection_pool_class: type[SentinelConnectionPool] = ...,
|
|
429
|
+
**kwargs: Any,
|
|
430
|
+
) -> Redis[bytes]: ...
|
|
431
|
+
|
|
432
|
+
@overload
|
|
433
|
+
def replica_for(
|
|
434
|
+
self: Sentinel[str],
|
|
435
|
+
service_name: str,
|
|
436
|
+
redis_class: type[Redis[str]] = ...,
|
|
437
|
+
connection_pool_class: type[SentinelConnectionPool] = ...,
|
|
438
|
+
**kwargs: Any,
|
|
439
|
+
) -> Redis[str]: ...
|
|
440
|
+
|
|
441
|
+
def replica_for(
|
|
442
|
+
self,
|
|
443
|
+
service_name: str,
|
|
444
|
+
redis_class: type[Redis[Any]] = Redis[Any],
|
|
445
|
+
connection_pool_class: type[SentinelConnectionPool] = SentinelConnectionPool,
|
|
446
|
+
**kwargs: Any,
|
|
447
|
+
) -> Redis[bytes] | Redis[str]:
|
|
448
|
+
"""
|
|
449
|
+
Returns redis client instance for the :paramref:`service_name` replica(s).
|
|
450
|
+
|
|
451
|
+
A SentinelConnectionPool class is used to retrieve the replica's
|
|
452
|
+
address before establishing a new connection.
|
|
453
|
+
|
|
454
|
+
By default clients will be a redis.Redis instance. Specify a
|
|
455
|
+
different class to the :paramref:`redis_class` argument if you desire
|
|
456
|
+
something different.
|
|
457
|
+
|
|
458
|
+
The :paramref:`connection_pool_class` specifies the connection pool to use.
|
|
459
|
+
The SentinelConnectionPool will be used by default.
|
|
460
|
+
|
|
461
|
+
All other keyword arguments are merged with any :paramref:`Sentinel.connection_kwargs`
|
|
462
|
+
passed to this class and passed to the connection pool as keyword
|
|
463
|
+
arguments to be used to initialize Redis connections.
|
|
464
|
+
"""
|
|
465
|
+
kwargs["is_primary"] = False
|
|
466
|
+
connection_kwargs = dict(self.connection_kwargs)
|
|
467
|
+
connection_kwargs.update(kwargs)
|
|
468
|
+
|
|
469
|
+
return redis_class(
|
|
470
|
+
connection_pool=connection_pool_class(
|
|
471
|
+
service_name,
|
|
472
|
+
self,
|
|
473
|
+
**connection_kwargs,
|
|
474
|
+
),
|
|
475
|
+
cache=self.__cache,
|
|
476
|
+
type_adapter=self.__type_adapter,
|
|
477
|
+
)
|