redis 7.0.0b2__py3-none-any.whl → 7.0.1__py3-none-any.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.
- redis/__init__.py +1 -1
- redis/_parsers/base.py +6 -0
- redis/_parsers/helpers.py +64 -6
- redis/asyncio/client.py +14 -5
- redis/asyncio/cluster.py +5 -1
- redis/asyncio/connection.py +19 -1
- redis/asyncio/http/__init__.py +0 -0
- redis/asyncio/http/http_client.py +265 -0
- redis/asyncio/multidb/__init__.py +0 -0
- redis/asyncio/multidb/client.py +530 -0
- redis/asyncio/multidb/command_executor.py +339 -0
- redis/asyncio/multidb/config.py +210 -0
- redis/asyncio/multidb/database.py +69 -0
- redis/asyncio/multidb/event.py +84 -0
- redis/asyncio/multidb/failover.py +125 -0
- redis/asyncio/multidb/failure_detector.py +38 -0
- redis/asyncio/multidb/healthcheck.py +285 -0
- redis/background.py +204 -0
- redis/client.py +49 -27
- redis/cluster.py +9 -1
- redis/commands/core.py +64 -29
- redis/commands/json/commands.py +2 -2
- redis/commands/search/__init__.py +2 -2
- redis/commands/search/aggregation.py +24 -26
- redis/commands/search/commands.py +10 -10
- redis/commands/search/field.py +2 -2
- redis/commands/search/query.py +12 -12
- redis/connection.py +1613 -1263
- redis/data_structure.py +81 -0
- redis/event.py +84 -10
- redis/exceptions.py +8 -0
- redis/http/__init__.py +0 -0
- redis/http/http_client.py +425 -0
- redis/maint_notifications.py +18 -7
- redis/multidb/__init__.py +0 -0
- redis/multidb/circuit.py +144 -0
- redis/multidb/client.py +526 -0
- redis/multidb/command_executor.py +350 -0
- redis/multidb/config.py +207 -0
- redis/multidb/database.py +130 -0
- redis/multidb/event.py +89 -0
- redis/multidb/exception.py +17 -0
- redis/multidb/failover.py +125 -0
- redis/multidb/failure_detector.py +104 -0
- redis/multidb/healthcheck.py +282 -0
- redis/retry.py +14 -1
- redis/utils.py +34 -0
- {redis-7.0.0b2.dist-info → redis-7.0.1.dist-info}/METADATA +17 -4
- {redis-7.0.0b2.dist-info → redis-7.0.1.dist-info}/RECORD +51 -25
- {redis-7.0.0b2.dist-info → redis-7.0.1.dist-info}/WHEEL +0 -0
- {redis-7.0.0b2.dist-info → redis-7.0.1.dist-info}/licenses/LICENSE +0 -0
redis/maint_notifications.py
CHANGED
|
@@ -32,9 +32,8 @@ class EndpointType(enum.Enum):
|
|
|
32
32
|
|
|
33
33
|
if TYPE_CHECKING:
|
|
34
34
|
from redis.connection import (
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
ConnectionPool,
|
|
35
|
+
MaintNotificationsAbstractConnection,
|
|
36
|
+
MaintNotificationsAbstractConnectionPool,
|
|
38
37
|
)
|
|
39
38
|
|
|
40
39
|
|
|
@@ -501,7 +500,7 @@ class MaintNotificationsConfig:
|
|
|
501
500
|
return self.relaxed_timeout != -1
|
|
502
501
|
|
|
503
502
|
def get_endpoint_type(
|
|
504
|
-
self, host: str, connection: "
|
|
503
|
+
self, host: str, connection: "MaintNotificationsAbstractConnection"
|
|
505
504
|
) -> EndpointType:
|
|
506
505
|
"""
|
|
507
506
|
Determine the appropriate endpoint type for CLIENT MAINT_NOTIFICATIONS command.
|
|
@@ -558,7 +557,7 @@ class MaintNotificationsConfig:
|
|
|
558
557
|
class MaintNotificationsPoolHandler:
|
|
559
558
|
def __init__(
|
|
560
559
|
self,
|
|
561
|
-
pool:
|
|
560
|
+
pool: "MaintNotificationsAbstractConnectionPool",
|
|
562
561
|
config: MaintNotificationsConfig,
|
|
563
562
|
) -> None:
|
|
564
563
|
self.pool = pool
|
|
@@ -567,9 +566,19 @@ class MaintNotificationsPoolHandler:
|
|
|
567
566
|
self._lock = threading.RLock()
|
|
568
567
|
self.connection = None
|
|
569
568
|
|
|
570
|
-
def set_connection(self, connection: "
|
|
569
|
+
def set_connection(self, connection: "MaintNotificationsAbstractConnection"):
|
|
571
570
|
self.connection = connection
|
|
572
571
|
|
|
572
|
+
def get_handler_for_connection(self):
|
|
573
|
+
# Copy all data that should be shared between connections
|
|
574
|
+
# but each connection should have its own pool handler
|
|
575
|
+
# since each connection can be in a different state
|
|
576
|
+
copy = MaintNotificationsPoolHandler(self.pool, self.config)
|
|
577
|
+
copy._processed_notifications = self._processed_notifications
|
|
578
|
+
copy._lock = self._lock
|
|
579
|
+
copy.connection = None
|
|
580
|
+
return copy
|
|
581
|
+
|
|
573
582
|
def remove_expired_notifications(self):
|
|
574
583
|
with self._lock:
|
|
575
584
|
for notification in tuple(self._processed_notifications):
|
|
@@ -751,7 +760,9 @@ class MaintNotificationsConnectionHandler:
|
|
|
751
760
|
}
|
|
752
761
|
|
|
753
762
|
def __init__(
|
|
754
|
-
self,
|
|
763
|
+
self,
|
|
764
|
+
connection: "MaintNotificationsAbstractConnection",
|
|
765
|
+
config: MaintNotificationsConfig,
|
|
755
766
|
) -> None:
|
|
756
767
|
self.connection = connection
|
|
757
768
|
self.config = config
|
|
File without changes
|
redis/multidb/circuit.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Callable
|
|
4
|
+
|
|
5
|
+
import pybreaker
|
|
6
|
+
|
|
7
|
+
DEFAULT_GRACE_PERIOD = 60
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class State(Enum):
|
|
11
|
+
CLOSED = "closed"
|
|
12
|
+
OPEN = "open"
|
|
13
|
+
HALF_OPEN = "half-open"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CircuitBreaker(ABC):
|
|
17
|
+
@property
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def grace_period(self) -> float:
|
|
20
|
+
"""The grace period in seconds when the circle should be kept open."""
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
@grace_period.setter
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def grace_period(self, grace_period: float):
|
|
26
|
+
"""Set the grace period in seconds."""
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def state(self) -> State:
|
|
31
|
+
"""The current state of the circuit."""
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
@state.setter
|
|
35
|
+
@abstractmethod
|
|
36
|
+
def state(self, state: State):
|
|
37
|
+
"""Set current state of the circuit."""
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def database(self):
|
|
43
|
+
"""Database associated with this circuit."""
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
@database.setter
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def database(self, database):
|
|
49
|
+
"""Set database associated with this circuit."""
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
def on_state_changed(self, cb: Callable[["CircuitBreaker", State, State], None]):
|
|
54
|
+
"""Callback called when the state of the circuit changes."""
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class BaseCircuitBreaker(CircuitBreaker):
|
|
59
|
+
"""
|
|
60
|
+
Base implementation of Circuit Breaker interface.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def __init__(self, cb: pybreaker.CircuitBreaker):
|
|
64
|
+
self._cb = cb
|
|
65
|
+
self._state_pb_mapper = {
|
|
66
|
+
State.CLOSED: self._cb.close,
|
|
67
|
+
State.OPEN: self._cb.open,
|
|
68
|
+
State.HALF_OPEN: self._cb.half_open,
|
|
69
|
+
}
|
|
70
|
+
self._database = None
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def grace_period(self) -> float:
|
|
74
|
+
return self._cb.reset_timeout
|
|
75
|
+
|
|
76
|
+
@grace_period.setter
|
|
77
|
+
def grace_period(self, grace_period: float):
|
|
78
|
+
self._cb.reset_timeout = grace_period
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def state(self) -> State:
|
|
82
|
+
return State(value=self._cb.state.name)
|
|
83
|
+
|
|
84
|
+
@state.setter
|
|
85
|
+
def state(self, state: State):
|
|
86
|
+
self._state_pb_mapper[state]()
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def database(self):
|
|
90
|
+
return self._database
|
|
91
|
+
|
|
92
|
+
@database.setter
|
|
93
|
+
def database(self, database):
|
|
94
|
+
self._database = database
|
|
95
|
+
|
|
96
|
+
@abstractmethod
|
|
97
|
+
def on_state_changed(self, cb: Callable[["CircuitBreaker", State, State], None]):
|
|
98
|
+
"""Callback called when the state of the circuit changes."""
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class PBListener(pybreaker.CircuitBreakerListener):
|
|
103
|
+
"""Wrapper for callback to be compatible with pybreaker implementation."""
|
|
104
|
+
|
|
105
|
+
def __init__(
|
|
106
|
+
self,
|
|
107
|
+
cb: Callable[[CircuitBreaker, State, State], None],
|
|
108
|
+
database,
|
|
109
|
+
):
|
|
110
|
+
"""
|
|
111
|
+
Initialize a PBListener instance.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
cb: Callback function that will be called when the circuit breaker state changes.
|
|
115
|
+
database: Database instance associated with this circuit breaker.
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
self._cb = cb
|
|
119
|
+
self._database = database
|
|
120
|
+
|
|
121
|
+
def state_change(self, cb, old_state, new_state):
|
|
122
|
+
cb = PBCircuitBreakerAdapter(cb)
|
|
123
|
+
cb.database = self._database
|
|
124
|
+
old_state = State(value=old_state.name)
|
|
125
|
+
new_state = State(value=new_state.name)
|
|
126
|
+
self._cb(cb, old_state, new_state)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class PBCircuitBreakerAdapter(BaseCircuitBreaker):
|
|
130
|
+
def __init__(self, cb: pybreaker.CircuitBreaker):
|
|
131
|
+
"""
|
|
132
|
+
Initialize a PBCircuitBreakerAdapter instance.
|
|
133
|
+
|
|
134
|
+
This adapter wraps pybreaker's CircuitBreaker implementation to make it compatible
|
|
135
|
+
with our CircuitBreaker interface.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
cb: A pybreaker CircuitBreaker instance to be adapted.
|
|
139
|
+
"""
|
|
140
|
+
super().__init__(cb)
|
|
141
|
+
|
|
142
|
+
def on_state_changed(self, cb: Callable[["CircuitBreaker", State, State], None]):
|
|
143
|
+
listener = PBListener(cb, self.database)
|
|
144
|
+
self._cb.add_listener(listener)
|