@@ -41,9 +41,16 @@ def connect_to(self, address):
41
41
if str_if_bytes (self .read_response ()) != "PONG" :
42
42
raise ConnectionError ("PING failed" )
43
43
44
- def _connect_retry (self ):
44
+ def _connect_retry (self , same_server : bool = False ):
45
45
if self ._sock :
46
46
return # already connected
47
+ # If same_server is True, it means that the connection
48
+ # is not rotating to the next slave (if the connection pool is not master)
49
+ if same_server :
50
+ self .connect_to (self .host , self .port )
51
+ return
52
+ # If same_server is False, connnect to master in master mode
53
+ # and rotate to the next slave in slave mode
47
54
if self .connection_pool .is_master :
48
55
self .connect_to (self .connection_pool .get_master_address ())
49
56
else :
@@ -54,8 +61,11 @@ def _connect_retry(self):
54
61
continue
55
62
raise SlaveNotFoundError # Never be here
56
63
57
- def connect (self ):
58
- return self .retry .call_with_retry (self ._connect_retry , lambda error : None )
64
+ def connect (self , same_server : bool = False ):
65
+ return self .retry .call_with_retry (
66
+ lambda : self ._connect_retry (same_server ),
67
+ lambda error : None
68
+ )
59
69
60
70
def read_response (
61
71
self ,
@@ -195,6 +205,29 @@ def rotate_slaves(self):
195
205
"Round-robin slave balancer"
196
206
return self .proxy .rotate_slaves ()
197
207
208
+ def ensure_connection_connected_to_address (self , connection : SentinelManagedConnection ):
209
+ """
210
+ Ensure the connection is already connected to the server that this connection
211
+ object wants to connect to
212
+
213
+ Similar to self.ensure_connection, but calling connection.connect()
214
+ in SentinelManagedConnection (replica mode) will cause the
215
+ connection object to connect to the next replica in rotation,
216
+ and we don't wnat behavior. Look at get_connection inline docs for details.
217
+
218
+ Here, we just try to make sure that the connection is already connected
219
+ to the replica we wanted it to.
220
+ """
221
+ connection .connect (same_address = True )
222
+ try :
223
+ if connection .can_read (same_address = True ) and connection .client_cache is None :
224
+ raise ConnectionError ("Connection has data" )
225
+ except (ConnectionError , OSError ):
226
+ connection .disconnect ()
227
+ connection .connect (same_address = True )
228
+ if connection .can_read ():
229
+ raise ConnectionError ("Connection has data" )
230
+
198
231
def cleanup_scan (self , ** options ):
199
232
"""
200
233
Remove the SCAN ITER family command's request id from the dictionary
@@ -248,6 +281,7 @@ def get_connection(
248
281
connection = self .make_connection ()
249
282
assert connection
250
283
self ._in_use_connections .add (connection )
284
+ breakpoint ()
251
285
try :
252
286
# Ensure this connection is connected to Redis
253
287
# If this is the first scan request, it will
@@ -259,7 +293,9 @@ def get_connection(
259
293
# This will connect to the host and port of the replica
260
294
else :
261
295
connection .connect_to_address (server_host , server_port )
262
- self .ensure_connection (connection )
296
+ breakpoint ()
297
+ self .ensure_connection_connected_to_address (connection )
298
+ breakpoint ()
263
299
except BaseException :
264
300
# Release the connection back to the pool so that we don't
265
301
# leak it
@@ -270,6 +306,7 @@ def get_connection(
270
306
connection .host ,
271
307
connection .port ,
272
308
)
309
+ breakpoint ()
273
310
return connection
274
311
275
312
0 commit comments