@@ -183,7 +183,6 @@ def __init__(self, **configs):
183
183
self .cluster = ClusterMetadata (** self .config )
184
184
self ._topics = set () # empty set will fetch all topic metadata
185
185
self ._metadata_refresh_in_progress = False
186
- self ._last_no_node_available_ms = 0
187
186
self ._selector = self .config ['selector' ]()
188
187
self ._conns = {}
189
188
self ._connecting = set ()
@@ -700,57 +699,62 @@ def _maybe_refresh_metadata(self):
700
699
int: milliseconds until next refresh
701
700
"""
702
701
ttl = self .cluster .ttl ()
703
- next_reconnect_ms = self ._last_no_node_available_ms + self .cluster .refresh_backoff ()
704
- next_reconnect_ms = max (next_reconnect_ms - time .time () * 1000 , 0 )
705
- wait_for_in_progress_ms = 9999999999 if self ._metadata_refresh_in_progress else 0
706
- timeout = max (ttl , next_reconnect_ms , wait_for_in_progress_ms )
707
-
708
- if timeout == 0 :
709
- node_id = self .least_loaded_node ()
710
- if node_id is None :
711
- log .debug ("Give up sending metadata request since no node is available" )
712
- # mark the timestamp for no node available to connect
713
- self ._last_no_node_available_ms = time .time () * 1000
714
- return timeout
715
-
716
- topics = list (self ._topics )
717
- if self .cluster .need_all_topic_metadata :
718
- if self .config ['api_version' ] < (0 , 10 ):
719
- topics = []
720
- else :
721
- topics = None
702
+ wait_for_in_progress_ms = self .config ['request_timeout_ms' ] if self ._metadata_refresh_in_progress else 0
703
+ metadata_timeout = max (ttl , wait_for_in_progress_ms )
722
704
723
- if self ._can_send_request (node_id ):
724
- if self .config ['api_version' ] < (0 , 10 ):
725
- api_version = 0
726
- else :
727
- api_version = 1
728
- request = MetadataRequest [api_version ](topics )
729
- log .debug ("Sending metadata request %s to node %s" , request , node_id )
730
- future = self .send (node_id , request )
731
- future .add_callback (self .cluster .update_metadata )
732
- future .add_errback (self .cluster .failed_update )
733
-
734
- self ._metadata_refresh_in_progress = True
735
- def refresh_done (val_or_error ):
736
- self ._metadata_refresh_in_progress = False
737
- future .add_callback (refresh_done )
738
- future .add_errback (refresh_done )
739
-
740
- elif self ._can_connect (node_id ):
741
- log .debug ("Initializing connection to node %s for metadata request" , node_id )
742
- self ._maybe_connect (node_id )
743
- # If _maybe_connect failed immediately, this node will be put into blackout and we
744
- # should allow immediately retrying in case there is another candidate node. If it
745
- # is still connecting, the worst case is that we end up setting a longer timeout
746
- # on the next round and then wait for the response.
705
+ if metadata_timeout > 0 :
706
+ return metadata_timeout
707
+
708
+ # Beware that the behavior of this method and the computation of
709
+ # timeouts for poll() are highly dependent on the behavior of
710
+ # least_loaded_node()
711
+ node_id = self .least_loaded_node ()
712
+ if node_id is None :
713
+ log .debug ("Give up sending metadata request since no node is available" );
714
+ return self .config ['reconnect_backoff_ms' ]
715
+
716
+ topics = list (self ._topics )
717
+ if self .cluster .need_all_topic_metadata :
718
+ if self .config ['api_version' ] < (0 , 10 ):
719
+ topics = []
747
720
else :
748
- # connected, but can't send more OR connecting
749
- # In either case, we just need to wait for a network event to let us know the selected
750
- # connection might be usable again.
751
- self ._last_no_node_available_ms = time .time () * 1000
721
+ topics = None
752
722
753
- return timeout
723
+ if self ._can_send_request (node_id ):
724
+ if self .config ['api_version' ] < (0 , 10 ):
725
+ api_version = 0
726
+ else :
727
+ api_version = 1
728
+ request = MetadataRequest [api_version ](topics )
729
+ log .debug ("Sending metadata request %s to node %s" , request , node_id )
730
+ future = self .send (node_id , request )
731
+ future .add_callback (self .cluster .update_metadata )
732
+ future .add_errback (self .cluster .failed_update )
733
+
734
+ self ._metadata_refresh_in_progress = True
735
+ def refresh_done (val_or_error ):
736
+ self ._metadata_refresh_in_progress = False
737
+ future .add_callback (refresh_done )
738
+ future .add_errback (refresh_done )
739
+ return self .config ['request_timeout_ms' ]
740
+
741
+ # If there's any connection establishment underway, wait until it completes. This prevents
742
+ # the client from unnecessarily connecting to additional nodes while a previous connection
743
+ # attempt has not been completed.
744
+ if self ._connecting :
745
+ # Strictly the timeout we should return here is "connect timeout", but as we don't
746
+ # have such application level configuration, using request timeout instead.
747
+ return self .config ['request_timeout_ms' ]
748
+
749
+ if self ._can_connect (node_id ):
750
+ log .debug ("Initializing connection to node %s for metadata request" , node_id )
751
+ self ._maybe_connect (node_id )
752
+ return self .config ['reconnect_backoff_ms' ]
753
+
754
+ # connected but can't send more, OR connecting
755
+ # In either case we just need to wait for a network event
756
+ # to let us know the selected connection might be usable again.
757
+ return float ('inf' )
754
758
755
759
def schedule (self , task , at ):
756
760
"""Schedule a new task to be executed at the given time.
0 commit comments