88import time
99
1010import six
11+ import sys
1112
1213try :
1314 from Queue import Empty , Queue
1617
1718from kafka .common import (
1819 FetchRequest , OffsetRequest ,
19- ConsumerFetchSizeTooSmall , ConsumerNoMoreData
20+ ConsumerFetchSizeTooSmall , ConsumerNoMoreData ,
21+ UnknownTopicOrPartitionError , NotLeaderForPartitionError ,
22+ OffsetOutOfRangeError , check_error
2023)
2124from .base import (
2225 Consumer ,
@@ -94,6 +97,10 @@ class SimpleConsumer(Consumer):
9497 message in the iterator before exiting. None means no
9598 timeout, so it will wait forever.
9699
100+ auto_offset_reset: default largest. Reset partition offsets upon
101+ OffsetOutOfRangeError. Valid values are largest and smallest.
102+ Otherwise, do not reset the offsets and raise OffsetOutOfRangeError.
103+
97104 Auto commit details:
98105 If both auto_commit_every_n and auto_commit_every_t are set, they will
99106 reset one another when one is triggered. These triggers simply call the
@@ -106,7 +113,8 @@ def __init__(self, client, group, topic, auto_commit=True, partitions=None,
106113 fetch_size_bytes = FETCH_MIN_BYTES ,
107114 buffer_size = FETCH_BUFFER_SIZE_BYTES ,
108115 max_buffer_size = MAX_FETCH_BUFFER_SIZE_BYTES ,
109- iter_timeout = None ):
116+ iter_timeout = None ,
117+ auto_offset_reset = 'largest' ):
110118 super (SimpleConsumer , self ).__init__ (
111119 client , group , topic ,
112120 partitions = partitions ,
@@ -125,12 +133,38 @@ def __init__(self, client, group, topic, auto_commit=True, partitions=None,
125133 self .fetch_min_bytes = fetch_size_bytes
126134 self .fetch_offsets = self .offsets .copy ()
127135 self .iter_timeout = iter_timeout
136+ self .auto_offset_reset = auto_offset_reset
128137 self .queue = Queue ()
129138
130139 def __repr__ (self ):
131140 return '<SimpleConsumer group=%s, topic=%s, partitions=%s>' % \
132141 (self .group , self .topic , str (self .offsets .keys ()))
133142
143+ def reset_partition_offset (self , partition ):
144+ LATEST = - 1
145+ EARLIEST = - 2
146+ if self .auto_offset_reset == 'largest' :
147+ reqs = [OffsetRequest (self .topic , partition , LATEST , 1 )]
148+ elif self .auto_offset_reset == 'smallest' :
149+ reqs = [OffsetRequest (self .topic , partition , EARLIEST , 1 )]
150+ else :
151+ # Let's raise an reasonable exception type if user calls
152+ # outside of an exception context
153+ if sys .exc_info () == (None , None , None ):
154+ raise OffsetOutOfRangeError ('Cannot reset partition offsets without a '
155+ 'valid auto_offset_reset setting '
156+ '(largest|smallest)' )
157+ # Otherwise we should re-raise the upstream exception
158+ # b/c it typically includes additional data about
159+ # the request that triggered it, and we do not want to drop that
160+ raise
161+
162+ # send_offset_request
163+ (resp , ) = self .client .send_offset_request (reqs )
164+ check_error (resp )
165+ self .offsets [partition ] = resp .offsets [0 ]
166+ self .fetch_offsets [partition ] = resp .offsets [0 ]
167+
134168 def provide_partition_info (self ):
135169 """
136170 Indicates that partition info must be returned by the consumer
@@ -297,10 +331,27 @@ def _fetch(self):
297331 responses = self .client .send_fetch_request (
298332 requests ,
299333 max_wait_time = int (self .fetch_max_wait_time ),
300- min_bytes = self .fetch_min_bytes )
334+ min_bytes = self .fetch_min_bytes ,
335+ fail_on_error = False
336+ )
301337
302338 retry_partitions = {}
303339 for resp in responses :
340+
341+ try :
342+ check_error (resp )
343+ except (UnknownTopicOrPartitionError , NotLeaderForPartitionError ):
344+ self .client .reset_topic_metadata (resp .topic )
345+ raise
346+ except OffsetOutOfRangeError :
347+ log .warning ("OffsetOutOfRangeError for %s - %d. "
348+ "Resetting partition offset..." ,
349+ resp .topic , resp .partition )
350+ self .reset_partition_offset (resp .partition )
351+ # Retry this partition
352+ retry_partitions [resp .partition ] = partitions [resp .partition ]
353+ continue
354+
304355 partition = resp .partition
305356 buffer_size = partitions [partition ]
306357 try :
0 commit comments