@@ -662,20 +662,49 @@ def unschedule(self, task):
662662 self ._delayed_tasks .remove (task )
663663
664664 def check_version (self , node_id = None , timeout = 2 , strict = False ):
665- """Attempt to guess the broker version"""
666- if node_id is None :
667- node_id = self .least_loaded_node ()
668- if node_id is None :
665+ """Attempt to guess a broker version
666+
667+ Note: it is possible that this method blocks longer than the
668+ specified timeout. This can happen if the entire cluster
669+ is down and the client enters a bootstrap backoff sleep.
670+ This is only possible if node_id is None.
671+
672+ Returns: version str, i.e. '0.10', '0.9', '0.8.2', '0.8.1', '0.8.0'
673+
674+ Raises:
675+ NodeNotReadyError (if node_id is provided)
676+ NoBrokersAvailable (if node_id is None)
677+ UnrecognizedBrokerVersion: please file bug if seen!
678+ AssertionError (if strict=True): please file bug if seen!
679+ """
680+ end = time .time () + timeout
681+ while time .time () < end :
682+
683+ # It is possible that least_loaded_node falls back to bootstrap,
684+ # which can block for an increasing backoff period
685+ try_node = node_id or self .least_loaded_node ()
686+ if try_node is None :
669687 raise Errors .NoBrokersAvailable ()
688+ self ._maybe_connect (try_node )
689+ conn = self ._conns [try_node ]
670690
671- # We will be intentionally causing socket failures
672- # and should not trigger metadata refresh
673- self ._refresh_on_disconnects = False
674- self ._maybe_connect (node_id )
675- conn = self ._conns [node_id ]
676- version = conn .check_version ()
677- self ._refresh_on_disconnects = True
678- return version
691+ # We will intentionally cause socket failures
692+ # These should not trigger metadata refresh
693+ self ._refresh_on_disconnects = False
694+ try :
695+ remaining = end - time .time ()
696+ version = conn .check_version (timeout = remaining , strict = strict )
697+ return version
698+ except Errors .NodeNotReadyError :
699+ # Only raise to user if this is a node-specific request
700+ if node_id is not None :
701+ raise
702+ finally :
703+ self ._refresh_on_disconnects = True
704+
705+ # Timeout
706+ else :
707+ raise Errors .NoBrokersAvailable ()
679708
680709 def wakeup (self ):
681710 if self ._wake_w .send (b'x' ) != 1 :
0 commit comments