@@ -3501,22 +3501,37 @@ def _cancel_timer(self):
35013501 if self ._timer :
35023502 self ._timer .cancel ()
35033503
3504- def _on_timeout (self ):
3504+ def _on_timeout (self , _attempts = 0 ):
3505+ """
3506+ Called when the request associated with this ResponseFuture times out.
35053507
3506- try :
3507- self ._connection ._requests .pop (self ._req_id )
3508- # This prevents the race condition of the
3509- # event loop thread just receiving the waited message
3510- # If it arrives after this, it will be ignored
3511- except KeyError :
3508+ This function may reschedule itself. The ``_attempts`` parameter tracks
3509+ the number of times this has happened. This parameter should only be
3510+ set in those cases, where ``_on_timeout`` reschedules itself.
3511+ """
3512+ # PYTHON-853: for short timeouts, we sometimes race with our __init__
3513+ if self ._connection is None and _attempts < 3 :
3514+ self ._timer = self .session .cluster .connection_class .create_timer (
3515+ 0.01 ,
3516+ partial (self ._on_timeout , _attempts = _attempts + 1 )
3517+ )
35123518 return
35133519
3514- pool = self .session ._pools .get (self ._current_host )
3515- if pool and not pool .is_shutdown :
3516- with self ._connection .lock :
3517- self ._connection .request_ids .append (self ._req_id )
3520+ if self ._connection is not None :
3521+ try :
3522+ self ._connection ._requests .pop (self ._req_id )
3523+ # This prevents the race condition of the
3524+ # event loop thread just receiving the waited message
3525+ # If it arrives after this, it will be ignored
3526+ except KeyError :
3527+ return
3528+
3529+ pool = self .session ._pools .get (self ._current_host )
3530+ if pool and not pool .is_shutdown :
3531+ with self ._connection .lock :
3532+ self ._connection .request_ids .append (self ._req_id )
35183533
3519- pool .return_connection (self ._connection )
3534+ pool .return_connection (self ._connection )
35203535
35213536 errors = self ._errors
35223537 if not errors :
0 commit comments