1
1
import logging
2
2
import threading
3
3
import time
4
- from typing import TYPE_CHECKING
4
+ from abc import ABC , abstractmethod
5
+ from typing import TYPE_CHECKING , Optional
5
6
6
7
from redis .typing import Number
7
8
8
9
if TYPE_CHECKING :
9
10
from redis .connection import ConnectionInterface , ConnectionPool
10
11
11
12
12
- class MaintenanceEvent :
13
+ class MaintenanceEvent ( ABC ) :
13
14
"""
14
15
Base class for maintenance events sent through push messages by Redis server.
15
16
16
- This class provides common TTL (Time-To-Live) functionality for all
17
- maintenance events .
17
+ This class provides common functionality for all maintenance events including
18
+ unique identification and TTL (Time-To-Live) functionality .
18
19
19
20
Attributes:
21
+ id (int): Unique identifier for this event
20
22
ttl (int): Time-to-live in seconds for this notification
21
23
creation_time (float): Timestamp when the notification was created/read
22
24
"""
23
25
24
- def __init__ (self , ttl : int ):
26
+ def __init__ (self , id : int , ttl : int ):
25
27
"""
26
- Initialize a new MaintenanceEvent with TTL functionality.
28
+ Initialize a new MaintenanceEvent with unique ID and TTL functionality.
27
29
28
30
Args:
31
+ id (int): Unique identifier for this event
29
32
ttl (int): Time-to-live in seconds for this notification
30
33
"""
34
+ self .id = id
31
35
self .ttl = ttl
32
- self .creation_time = int ( time .time () )
36
+ self .creation_time = time .monotonic ( )
33
37
self .expire_at = self .creation_time + self .ttl
34
38
35
39
def is_expired (self ) -> bool :
@@ -40,7 +44,49 @@ def is_expired(self) -> bool:
40
44
Returns:
41
45
bool: True if the event has expired, False otherwise
42
46
"""
43
- return int (time .time ()) > (self .creation_time + self .ttl )
47
+ return time .monotonic () > (self .creation_time + self .ttl )
48
+
49
+ @abstractmethod
50
+ def __repr__ (self ) -> str :
51
+ """
52
+ Return a string representation of the maintenance event.
53
+
54
+ This method must be implemented by all concrete subclasses.
55
+
56
+ Returns:
57
+ str: String representation of the event
58
+ """
59
+ pass
60
+
61
+ @abstractmethod
62
+ def __eq__ (self , other ) -> bool :
63
+ """
64
+ Compare two maintenance events for equality.
65
+
66
+ This method must be implemented by all concrete subclasses.
67
+ Events are typically considered equal if they have the same id
68
+ and are of the same type.
69
+
70
+ Args:
71
+ other: The other object to compare with
72
+
73
+ Returns:
74
+ bool: True if the events are equal, False otherwise
75
+ """
76
+ pass
77
+
78
+ @abstractmethod
79
+ def __hash__ (self ) -> int :
80
+ """
81
+ Return a hash value for the maintenance event.
82
+
83
+ This method must be implemented by all concrete subclasses to allow
84
+ instances to be used in sets and as dictionary keys.
85
+
86
+ Returns:
87
+ int: Hash value for the event
88
+ """
89
+ pass
44
90
45
91
46
92
class NodeMovingEvent (MaintenanceEvent ):
@@ -49,25 +95,27 @@ class NodeMovingEvent(MaintenanceEvent):
49
95
during cluster rebalancing or maintenance operations.
50
96
"""
51
97
52
- def __init__ (self , new_node_host : str , new_node_port : int , ttl : int ):
98
+ def __init__ (self , id : int , new_node_host : str , new_node_port : int , ttl : int ):
53
99
"""
54
100
Initialize a new NodeMovingEvent.
55
101
56
102
Args:
103
+ id (int): Unique identifier for this event
57
104
new_node_host (str): Hostname or IP address of the new replacement node
58
105
new_node_port (int): Port number of the new replacement node
59
106
ttl (int): Time-to-live in seconds for this notification
60
107
"""
61
- super ().__init__ (ttl )
108
+ super ().__init__ (id , ttl )
62
109
self .new_node_host = new_node_host
63
110
self .new_node_port = new_node_port
64
111
65
112
def __repr__ (self ) -> str :
66
113
expiry_time = self .expire_at
67
- remaining = max (0 , expiry_time - time .time ())
114
+ remaining = max (0 , expiry_time - time .monotonic ())
68
115
69
116
return (
70
117
f"{ self .__class__ .__name__ } ("
118
+ f"id={ self .id } , "
71
119
f"new_node_host='{ self .new_node_host } ', "
72
120
f"new_node_port={ self .new_node_port } , "
73
121
f"ttl={ self .ttl } , "
@@ -81,12 +129,13 @@ def __repr__(self) -> str:
81
129
def __eq__ (self , other ) -> bool :
82
130
"""
83
131
Two NodeMovingEvent events are considered equal if they have the same
84
- new_node_host and new_node_port.
132
+ id, new_node_host, and new_node_port.
85
133
"""
86
134
if not isinstance (other , NodeMovingEvent ):
87
135
return False
88
136
return (
89
- self .new_node_host == other .new_node_host
137
+ self .id == other .id
138
+ and self .new_node_host == other .new_node_host
90
139
and self .new_node_port == other .new_node_port
91
140
)
92
141
@@ -96,9 +145,9 @@ def __hash__(self) -> int:
96
145
instances to be used in sets and as dictionary keys.
97
146
98
147
Returns:
99
- int: Hash value based on new_node_host and new_node_port
148
+ int: Hash value based on event type, id, new_node_host, and new_node_port
100
149
"""
101
- return hash ((self .__class__ , self .new_node_host , self .new_node_port ))
150
+ return hash ((self .__class__ , self .id , self . new_node_host , self .new_node_port ))
102
151
103
152
104
153
class NodeMigratingEvent (MaintenanceEvent ):
@@ -109,17 +158,19 @@ class NodeMigratingEvent(MaintenanceEvent):
109
158
during cluster rebalancing or maintenance operations.
110
159
111
160
Args:
161
+ id (int): Unique identifier for this event
112
162
ttl (int): Time-to-live in seconds for this notification
113
163
"""
114
164
115
- def __init__ (self , ttl : int ):
116
- super ().__init__ (ttl )
165
+ def __init__ (self , id : int , ttl : int ):
166
+ super ().__init__ (id , ttl )
117
167
118
168
def __repr__ (self ) -> str :
119
169
expiry_time = self .creation_time + self .ttl
120
- remaining = max (0 , expiry_time - time .time ())
170
+ remaining = max (0 , expiry_time - time .monotonic ())
121
171
return (
122
172
f"{ self .__class__ .__name__ } ("
173
+ f"id={ self .id } , "
123
174
f"ttl={ self .ttl } , "
124
175
f"creation_time={ self .creation_time } , "
125
176
f"expires_at={ expiry_time } , "
@@ -128,6 +179,25 @@ def __repr__(self) -> str:
128
179
f")"
129
180
)
130
181
182
+ def __eq__ (self , other ) -> bool :
183
+ """
184
+ Two NodeMigratingEvent events are considered equal if they have the same
185
+ id and are of the same type.
186
+ """
187
+ if not isinstance (other , NodeMigratingEvent ):
188
+ return False
189
+ return self .id == other .id and type (self ) is type (other )
190
+
191
+ def __hash__ (self ) -> int :
192
+ """
193
+ Return a hash value for the event to allow
194
+ instances to be used in sets and as dictionary keys.
195
+
196
+ Returns:
197
+ int: Hash value based on event type and id
198
+ """
199
+ return hash ((self .__class__ , self .id ))
200
+
131
201
132
202
class NodeMigratedEvent (MaintenanceEvent ):
133
203
"""
@@ -137,19 +207,20 @@ class NodeMigratedEvent(MaintenanceEvent):
137
207
to other nodes during cluster rebalancing or maintenance operations.
138
208
139
209
Args:
140
- ttl (int): Time-to-live in seconds for this notification
210
+ id (int): Unique identifier for this event
141
211
"""
142
212
143
213
DEFAULT_TTL = 5
144
214
145
- def __init__ (self ):
146
- super ().__init__ (NodeMigratedEvent .DEFAULT_TTL )
215
+ def __init__ (self , id : int ):
216
+ super ().__init__ (id , NodeMigratedEvent .DEFAULT_TTL )
147
217
148
218
def __repr__ (self ) -> str :
149
219
expiry_time = self .creation_time + self .ttl
150
- remaining = max (0 , expiry_time - time .time ())
220
+ remaining = max (0 , expiry_time - time .monotonic ())
151
221
return (
152
222
f"{ self .__class__ .__name__ } ("
223
+ f"id={ self .id } , "
153
224
f"ttl={ self .ttl } , "
154
225
f"creation_time={ self .creation_time } , "
155
226
f"expires_at={ expiry_time } , "
@@ -158,6 +229,25 @@ def __repr__(self) -> str:
158
229
f")"
159
230
)
160
231
232
+ def __eq__ (self , other ) -> bool :
233
+ """
234
+ Two NodeMigratedEvent events are considered equal if they have the same
235
+ id and are of the same type.
236
+ """
237
+ if not isinstance (other , NodeMigratedEvent ):
238
+ return False
239
+ return self .id == other .id and type (self ) is type (other )
240
+
241
+ def __hash__ (self ) -> int :
242
+ """
243
+ Return a hash value for the event to allow
244
+ instances to be used in sets and as dictionary keys.
245
+
246
+ Returns:
247
+ int: Hash value based on event type and id
248
+ """
249
+ return hash ((self .__class__ , self .id ))
250
+
161
251
162
252
class MaintenanceEventsConfig :
163
253
"""
@@ -173,7 +263,7 @@ def __init__(
173
263
self ,
174
264
enabled : bool = False ,
175
265
proactive_reconnect : bool = True ,
176
- relax_timeout : Number = 20 ,
266
+ relax_timeout : Optional [ Number ] = 20 ,
177
267
):
178
268
"""
179
269
Initialize a new MaintenanceEventsConfig.
0 commit comments