1313from kafka .future import Future
1414from kafka .metrics .stats import Avg , Count , Max , Rate
1515from kafka .protocol .fetch import FetchRequest
16- from kafka .protocol .offset import (
17- OffsetRequest , OffsetResetStrategy , UNKNOWN_OFFSET
16+ from kafka .protocol .list_offsets import (
17+ ListOffsetsRequest , OffsetResetStrategy , UNKNOWN_OFFSET
1818)
1919from kafka .record import MemoryRecords
2020from kafka .serializer import Deserializer
@@ -272,7 +272,7 @@ def _retrieve_offsets(self, timestamps, timeout_ms=float("inf")):
272272 if not timestamps :
273273 return {}
274274
275- future = self ._send_offset_requests (timestamps )
275+ future = self ._send_list_offsets_requests (timestamps )
276276 self ._client .poll (future = future , timeout_ms = remaining_ms )
277277
278278 if future .succeeded ():
@@ -519,7 +519,7 @@ def _deserialize(self, f, topic, bytes_):
519519 return f .deserialize (topic , bytes_ )
520520 return f (bytes_ )
521521
522- def _send_offset_requests (self , timestamps ):
522+ def _send_list_offsets_requests (self , timestamps ):
523523 """Fetch offsets for each partition in timestamps dict. This may send
524524 request to multiple nodes, based on who is Leader for partition.
525525
@@ -564,13 +564,13 @@ def on_fail(err):
564564 list_offsets_future .failure (err )
565565
566566 for node_id , timestamps in six .iteritems (timestamps_by_node ):
567- _f = self ._send_offset_request (node_id , timestamps )
567+ _f = self ._send_list_offsets_request (node_id , timestamps )
568568 _f .add_callback (on_success )
569569 _f .add_errback (on_fail )
570570 return list_offsets_future
571571
572- def _send_offset_request (self , node_id , timestamps ):
573- version = self ._client .api_version (OffsetRequest , max_version = 1 )
572+ def _send_list_offsets_request (self , node_id , timestamps ):
573+ version = self ._client .api_version (ListOffsetsRequest , max_version = 3 )
574574 by_topic = collections .defaultdict (list )
575575 for tp , timestamp in six .iteritems (timestamps ):
576576 if version >= 1 :
@@ -579,28 +579,39 @@ def _send_offset_request(self, node_id, timestamps):
579579 data = (tp .partition , timestamp , 1 )
580580 by_topic [tp .topic ].append (data )
581581
582- request = OffsetRequest [version ](- 1 , list (six .iteritems (by_topic )))
582+ if version <= 1 :
583+ request = ListOffsetsRequest [version ](
584+ - 1 ,
585+ list (six .iteritems (by_topic )))
586+ else :
587+ request = ListOffsetsRequest [version ](
588+ - 1 ,
589+ self ._isolation_level ,
590+ list (six .iteritems (by_topic )))
591+
583592
584593 # Client returns a future that only fails on network issues
585594 # so create a separate future and attach a callback to update it
586595 # based on response error codes
587596 future = Future ()
588597
589598 _f = self ._client .send (node_id , request )
590- _f .add_callback (self ._handle_offset_response , future )
599+ _f .add_callback (self ._handle_list_offsets_response , future )
591600 _f .add_errback (lambda e : future .failure (e ))
592601 return future
593602
594- def _handle_offset_response (self , future , response ):
595- """Callback for the response of the list offset call above.
603+ def _handle_list_offsets_response (self , future , response ):
604+ """Callback for the response of the ListOffsets api call
596605
597606 Arguments:
598607 future (Future): the future to update based on response
599- response (OffsetResponse ): response from the server
608+ response (ListOffsetsResponse ): response from the server
600609
601610 Raises:
602611 AssertionError: if response does not match partition
603612 """
613+ if response .API_VERSION >= 2 and response .throttle_time_ms > 0 :
614+ log .warning ("ListOffsetsRequest throttled by broker (%d ms)" , response .throttle_time_ms )
604615 timestamp_offset_map = {}
605616 for topic , part_data in response .topics :
606617 for partition_info in part_data :
@@ -610,18 +621,18 @@ def _handle_offset_response(self, future, response):
610621 if error_type is Errors .NoError :
611622 if response .API_VERSION == 0 :
612623 offsets = partition_info [2 ]
613- assert len (offsets ) <= 1 , 'Expected OffsetResponse with one offset'
624+ assert len (offsets ) <= 1 , 'Expected ListOffsetsResponse with one offset'
614625 if not offsets :
615626 offset = UNKNOWN_OFFSET
616627 else :
617628 offset = offsets [0 ]
618- log .debug ("Handling v0 ListOffsetResponse response for %s. "
629+ log .debug ("Handling v0 ListOffsetsResponse response for %s. "
619630 "Fetched offset %s" , partition , offset )
620631 if offset != UNKNOWN_OFFSET :
621632 timestamp_offset_map [partition ] = (offset , None )
622633 else :
623634 timestamp , offset = partition_info [2 :]
624- log .debug ("Handling ListOffsetResponse response for %s. "
635+ log .debug ("Handling ListOffsetsResponse response for %s. "
625636 "Fetched offset %s, timestamp %s" ,
626637 partition , offset , timestamp )
627638 if offset != UNKNOWN_OFFSET :
@@ -638,7 +649,7 @@ def _handle_offset_response(self, future, response):
638649 future .failure (error_type (partition ))
639650 return
640651 elif error_type is Errors .UnknownTopicOrPartitionError :
641- log .warning ("Received unknown topic or partition error in ListOffset "
652+ log .warning ("Received unknown topic or partition error in ListOffsets "
642653 "request for partition %s. The topic/partition " +
643654 "may not exist or the user may not have Describe access "
644655 "to it." , partition )
0 commit comments