@@ -615,7 +615,7 @@ def partitions_for_topic(self, topic):
615615 partitions = cluster .partitions_for_topic (topic )
616616 return partitions
617617
618- def poll (self , timeout_ms = 0 , max_records = None , update_offsets = True ):
618+ def poll (self , timeout_ms = 0 , max_records = None , update_offsets = True , * , positions_timeout_ms = float ( "inf" ) ):
619619 """Fetch data from assigned topics / partitions.
620620
621621 Records are fetched and returned in batches by topic-partition.
@@ -656,7 +656,7 @@ def poll(self, timeout_ms=0, max_records=None, update_offsets=True):
656656 start = time .time ()
657657 remaining = timeout_ms
658658 while not self ._closed :
659- records = self ._poll_once (remaining , max_records , update_offsets = update_offsets )
659+ records = self ._poll_once (remaining , positions_timeout_ms , max_records , update_offsets = update_offsets )
660660 if records :
661661 return records
662662
@@ -668,7 +668,7 @@ def poll(self, timeout_ms=0, max_records=None, update_offsets=True):
668668
669669 return {}
670670
671- def _poll_once (self , timeout_ms , max_records , update_offsets = True ):
671+ def _poll_once (self , timeout_ms , positions_timeout_ms , max_records , update_offsets = True ):
672672 """Do one round of polling. In addition to checking for new data, this does
673673 any needed heart-beating, auto-commits, and offset updates.
674674
@@ -683,7 +683,7 @@ def _poll_once(self, timeout_ms, max_records, update_offsets=True):
683683 # Fetch positions if we have partitions we're subscribed to that we
684684 # don't know the offset for
685685 if not self ._subscription .has_all_fetch_positions ():
686- self ._update_fetch_positions (self ._subscription .missing_fetch_positions ())
686+ self ._update_fetch_positions (self ._subscription .missing_fetch_positions (), positions_timeout_ms )
687687
688688 # If data is available already, e.g. from a previous network client
689689 # poll() call to commit, then just return it immediately
@@ -714,7 +714,7 @@ def _poll_once(self, timeout_ms, max_records, update_offsets=True):
714714 records , _ = self ._fetcher .fetched_records (max_records , update_offsets = update_offsets )
715715 return records
716716
717- def position (self , partition ):
717+ def position (self , partition , timeout_ms = float ( "inf" ) ):
718718 """Get the offset of the next record that will be fetched
719719
720720 Arguments:
@@ -728,7 +728,7 @@ def position(self, partition):
728728 assert self ._subscription .is_assigned (partition ), 'Partition is not assigned'
729729 offset = self ._subscription .assignment [partition ].position
730730 if offset is None :
731- self ._update_fetch_positions ([partition ])
731+ self ._update_fetch_positions ([partition ], timeout_ms )
732732 offset = self ._subscription .assignment [partition ].position
733733 return offset
734734
@@ -1087,7 +1087,7 @@ def _use_consumer_group(self):
10871087 return False
10881088 return True
10891089
1090- def _update_fetch_positions (self , partitions ):
1090+ def _update_fetch_positions (self , partitions , timeout_ms ):
10911091 """Set the fetch position to the committed position (if there is one)
10921092 or reset it using the offset reset policy the user has configured.
10931093
@@ -1099,12 +1099,13 @@ def _update_fetch_positions(self, partitions):
10991099 NoOffsetForPartitionError: If no offset is stored for a given
11001100 partition and no offset reset policy is defined.
11011101 """
1102+ end_time = time .time () + timeout_ms / 1000
11021103 # Lookup any positions for partitions which are awaiting reset (which may be the
11031104 # case if the user called :meth:`seek_to_beginning` or :meth:`seek_to_end`. We do
11041105 # this check first to avoid an unnecessary lookup of committed offsets (which
11051106 # typically occurs when the user is manually assigning partitions and managing
11061107 # their own offsets).
1107- self ._fetcher .reset_offsets_if_needed (partitions )
1108+ self ._fetcher .reset_offsets_if_needed (partitions , timeout_ms )
11081109
11091110 if not self ._subscription .has_all_fetch_positions ():
11101111 # if we still don't have offsets for all partitions, then we should either seek
@@ -1115,7 +1116,8 @@ def _update_fetch_positions(self, partitions):
11151116 self ._coordinator .refresh_committed_offsets_if_needed ()
11161117
11171118 # Then, do any offset lookups in case some positions are not known
1118- self ._fetcher .update_fetch_positions (partitions )
1119+ update_timeout_ms = max (0.0 , 1000 * (end_time - time .time ()))
1120+ self ._fetcher .update_fetch_positions (partitions , update_timeout_ms )
11191121
11201122 def _message_generator_v2 (self ):
11211123 timeout_ms = 1000 * (self ._consumer_timeout - time .time ())
@@ -1145,7 +1147,8 @@ def _message_generator(self):
11451147 # Fetch offsets for any subscribed partitions that we arent tracking yet
11461148 if not self ._subscription .has_all_fetch_positions ():
11471149 partitions = self ._subscription .missing_fetch_positions ()
1148- self ._update_fetch_positions (partitions )
1150+ update_timeout_ms = max (0.0 , 1000 * (self ._consumer_timeout - time .time ()))
1151+ self ._update_fetch_positions (partitions , update_timeout_ms )
11491152
11501153 poll_ms = min ((1000 * (self ._consumer_timeout - time .time ())), self .config ['retry_backoff_ms' ])
11511154 self ._client .poll (timeout_ms = poll_ms )
0 commit comments