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