kafka-python 2.2.3__py2.py3-none-any.whl → 2.2.4__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kafka/client_async.py +7 -11
- kafka/consumer/fetcher.py +14 -9
- kafka/consumer/group.py +17 -19
- kafka/coordinator/base.py +42 -20
- kafka/coordinator/consumer.py +72 -39
- kafka/errors.py +12 -12
- kafka/producer/kafka.py +12 -24
- kafka/util.py +39 -19
- kafka/version.py +1 -1
- {kafka_python-2.2.3.dist-info → kafka_python-2.2.4.dist-info}/METADATA +1 -1
- {kafka_python-2.2.3.dist-info → kafka_python-2.2.4.dist-info}/RECORD +13 -13
- {kafka_python-2.2.3.dist-info → kafka_python-2.2.4.dist-info}/WHEEL +1 -1
- {kafka_python-2.2.3.dist-info → kafka_python-2.2.4.dist-info}/top_level.txt +0 -0
kafka/client_async.py
CHANGED
|
@@ -27,7 +27,7 @@ from kafka.metrics.stats import Avg, Count, Rate
|
|
|
27
27
|
from kafka.metrics.stats.rate import TimeUnit
|
|
28
28
|
from kafka.protocol.broker_api_versions import BROKER_API_VERSIONS
|
|
29
29
|
from kafka.protocol.metadata import MetadataRequest
|
|
30
|
-
from kafka.util import Dict, WeakMethod, ensure_valid_topic_name
|
|
30
|
+
from kafka.util import Dict, Timer, WeakMethod, ensure_valid_topic_name
|
|
31
31
|
# Although this looks unused, it actually monkey-patches socket.socketpair()
|
|
32
32
|
# and should be left in as long as we're using socket.socketpair() in this file
|
|
33
33
|
from kafka.vendor import socketpair # noqa: F401
|
|
@@ -645,12 +645,8 @@ class KafkaClient(object):
|
|
|
645
645
|
"""
|
|
646
646
|
if not isinstance(timeout_ms, (int, float, type(None))):
|
|
647
647
|
raise TypeError('Invalid type for timeout: %s' % type(timeout_ms))
|
|
648
|
+
timer = Timer(timeout_ms)
|
|
648
649
|
|
|
649
|
-
begin = time.time()
|
|
650
|
-
if timeout_ms is not None:
|
|
651
|
-
timeout_at = begin + (timeout_ms / 1000)
|
|
652
|
-
else:
|
|
653
|
-
timeout_at = begin + (self.config['request_timeout_ms'] / 1000)
|
|
654
650
|
# Loop for futures, break after first loop if None
|
|
655
651
|
responses = []
|
|
656
652
|
while True:
|
|
@@ -675,7 +671,7 @@ class KafkaClient(object):
|
|
|
675
671
|
if future is not None and future.is_done:
|
|
676
672
|
timeout = 0
|
|
677
673
|
else:
|
|
678
|
-
user_timeout_ms =
|
|
674
|
+
user_timeout_ms = timer.timeout_ms if timeout_ms is not None else self.config['request_timeout_ms']
|
|
679
675
|
idle_connection_timeout_ms = self._idle_expiry_manager.next_check_ms()
|
|
680
676
|
request_timeout_ms = self._next_ifr_request_timeout_ms()
|
|
681
677
|
log.debug("Timeouts: user %f, metadata %f, idle connection %f, request %f", user_timeout_ms, metadata_timeout_ms, idle_connection_timeout_ms, request_timeout_ms)
|
|
@@ -698,7 +694,7 @@ class KafkaClient(object):
|
|
|
698
694
|
break
|
|
699
695
|
elif future.is_done:
|
|
700
696
|
break
|
|
701
|
-
elif timeout_ms is not None and
|
|
697
|
+
elif timeout_ms is not None and timer.expired:
|
|
702
698
|
break
|
|
703
699
|
|
|
704
700
|
return responses
|
|
@@ -1175,16 +1171,16 @@ class KafkaClient(object):
|
|
|
1175
1171
|
This method is useful for implementing blocking behaviour on top of the non-blocking `NetworkClient`, use it with
|
|
1176
1172
|
care.
|
|
1177
1173
|
"""
|
|
1178
|
-
|
|
1174
|
+
timer = Timer(timeout_ms)
|
|
1179
1175
|
self.poll(timeout_ms=0)
|
|
1180
1176
|
if self.is_ready(node_id):
|
|
1181
1177
|
return True
|
|
1182
1178
|
|
|
1183
|
-
while not self.is_ready(node_id) and
|
|
1179
|
+
while not self.is_ready(node_id) and not timer.expired:
|
|
1184
1180
|
if self.connection_failed(node_id):
|
|
1185
1181
|
raise Errors.KafkaConnectionError("Connection to %s failed." % (node_id,))
|
|
1186
1182
|
self.maybe_connect(node_id)
|
|
1187
|
-
self.poll(timeout_ms=
|
|
1183
|
+
self.poll(timeout_ms=timer.timeout_ms)
|
|
1188
1184
|
return self.is_ready(node_id)
|
|
1189
1185
|
|
|
1190
1186
|
def send_and_receive(self, node_id, request):
|
kafka/consumer/fetcher.py
CHANGED
|
@@ -19,7 +19,7 @@ from kafka.protocol.list_offsets import (
|
|
|
19
19
|
from kafka.record import MemoryRecords
|
|
20
20
|
from kafka.serializer import Deserializer
|
|
21
21
|
from kafka.structs import TopicPartition, OffsetAndMetadata, OffsetAndTimestamp
|
|
22
|
-
from kafka.util import
|
|
22
|
+
from kafka.util import Timer
|
|
23
23
|
|
|
24
24
|
log = logging.getLogger(__name__)
|
|
25
25
|
|
|
@@ -230,7 +230,7 @@ class Fetcher(six.Iterator):
|
|
|
230
230
|
if not timestamps:
|
|
231
231
|
return {}
|
|
232
232
|
|
|
233
|
-
|
|
233
|
+
timer = Timer(timeout_ms, "Failed to get offsets by timestamps in %s ms" % (timeout_ms,))
|
|
234
234
|
timestamps = copy.copy(timestamps)
|
|
235
235
|
fetched_offsets = dict()
|
|
236
236
|
while True:
|
|
@@ -238,7 +238,7 @@ class Fetcher(six.Iterator):
|
|
|
238
238
|
return {}
|
|
239
239
|
|
|
240
240
|
future = self._send_list_offsets_requests(timestamps)
|
|
241
|
-
self._client.poll(future=future, timeout_ms=
|
|
241
|
+
self._client.poll(future=future, timeout_ms=timer.timeout_ms)
|
|
242
242
|
|
|
243
243
|
# Timeout w/o future completion
|
|
244
244
|
if not future.is_done:
|
|
@@ -256,12 +256,17 @@ class Fetcher(six.Iterator):
|
|
|
256
256
|
|
|
257
257
|
if future.exception.invalid_metadata or self._client.cluster.need_update:
|
|
258
258
|
refresh_future = self._client.cluster.request_update()
|
|
259
|
-
self._client.poll(future=refresh_future, timeout_ms=
|
|
259
|
+
self._client.poll(future=refresh_future, timeout_ms=timer.timeout_ms)
|
|
260
260
|
|
|
261
261
|
if not future.is_done:
|
|
262
262
|
break
|
|
263
263
|
else:
|
|
264
|
-
|
|
264
|
+
if timer.timeout_ms is None or timer.timeout_ms > self.config['retry_backoff_ms']:
|
|
265
|
+
time.sleep(self.config['retry_backoff_ms'] / 1000)
|
|
266
|
+
else:
|
|
267
|
+
time.sleep(timer.timeout_ms / 1000)
|
|
268
|
+
|
|
269
|
+
timer.maybe_raise()
|
|
265
270
|
|
|
266
271
|
raise Errors.KafkaTimeoutError(
|
|
267
272
|
"Failed to get offsets by timestamps in %s ms" % (timeout_ms,))
|
|
@@ -418,7 +423,7 @@ class Fetcher(six.Iterator):
|
|
|
418
423
|
expire_at = time.time() + self.config['request_timeout_ms'] / 1000
|
|
419
424
|
self._subscriptions.set_reset_pending(partitions, expire_at)
|
|
420
425
|
|
|
421
|
-
def on_success(result):
|
|
426
|
+
def on_success(timestamps_and_epochs, result):
|
|
422
427
|
fetched_offsets, partitions_to_retry = result
|
|
423
428
|
if partitions_to_retry:
|
|
424
429
|
self._subscriptions.reset_failed(partitions_to_retry, time.time() + self.config['retry_backoff_ms'] / 1000)
|
|
@@ -428,7 +433,7 @@ class Fetcher(six.Iterator):
|
|
|
428
433
|
ts, _epoch = timestamps_and_epochs[partition]
|
|
429
434
|
self._reset_offset_if_needed(partition, ts, offset.offset)
|
|
430
435
|
|
|
431
|
-
def on_failure(error):
|
|
436
|
+
def on_failure(partitions, error):
|
|
432
437
|
self._subscriptions.reset_failed(partitions, time.time() + self.config['retry_backoff_ms'] / 1000)
|
|
433
438
|
self._client.cluster.request_update()
|
|
434
439
|
|
|
@@ -439,8 +444,8 @@ class Fetcher(six.Iterator):
|
|
|
439
444
|
log.error("Discarding error in ListOffsetResponse because another error is pending: %s", error)
|
|
440
445
|
|
|
441
446
|
future = self._send_list_offsets_request(node_id, timestamps_and_epochs)
|
|
442
|
-
future.add_callback(on_success)
|
|
443
|
-
future.add_errback(on_failure)
|
|
447
|
+
future.add_callback(on_success, timestamps_and_epochs)
|
|
448
|
+
future.add_errback(on_failure, partitions)
|
|
444
449
|
|
|
445
450
|
def _send_list_offsets_requests(self, timestamps):
|
|
446
451
|
"""Fetch offsets for each partition in timestamps dict. This may send
|
kafka/consumer/group.py
CHANGED
|
@@ -18,7 +18,7 @@ from kafka.coordinator.assignors.roundrobin import RoundRobinPartitionAssignor
|
|
|
18
18
|
from kafka.metrics import MetricConfig, Metrics
|
|
19
19
|
from kafka.protocol.list_offsets import OffsetResetStrategy
|
|
20
20
|
from kafka.structs import OffsetAndMetadata, TopicPartition
|
|
21
|
-
from kafka.util import
|
|
21
|
+
from kafka.util import Timer
|
|
22
22
|
from kafka.version import __version__
|
|
23
23
|
|
|
24
24
|
log = logging.getLogger(__name__)
|
|
@@ -679,41 +679,40 @@ class KafkaConsumer(six.Iterator):
|
|
|
679
679
|
assert not self._closed, 'KafkaConsumer is closed'
|
|
680
680
|
|
|
681
681
|
# Poll for new data until the timeout expires
|
|
682
|
-
|
|
682
|
+
timer = Timer(timeout_ms)
|
|
683
683
|
while not self._closed:
|
|
684
|
-
records = self._poll_once(
|
|
684
|
+
records = self._poll_once(timer, max_records, update_offsets=update_offsets)
|
|
685
685
|
if records:
|
|
686
686
|
return records
|
|
687
|
-
|
|
688
|
-
if inner_timeout_ms() <= 0:
|
|
687
|
+
elif timer.expired:
|
|
689
688
|
break
|
|
690
|
-
|
|
691
689
|
return {}
|
|
692
690
|
|
|
693
|
-
def _poll_once(self,
|
|
691
|
+
def _poll_once(self, timer, max_records, update_offsets=True):
|
|
694
692
|
"""Do one round of polling. In addition to checking for new data, this does
|
|
695
693
|
any needed heart-beating, auto-commits, and offset updates.
|
|
696
694
|
|
|
697
695
|
Arguments:
|
|
698
|
-
|
|
696
|
+
timer (Timer): The maximum time in milliseconds to block.
|
|
699
697
|
|
|
700
698
|
Returns:
|
|
701
699
|
dict: Map of topic to list of records (may be empty).
|
|
702
700
|
"""
|
|
703
|
-
|
|
704
|
-
if not self._coordinator.poll(timeout_ms=inner_timeout_ms()):
|
|
701
|
+
if not self._coordinator.poll(timeout_ms=timer.timeout_ms):
|
|
705
702
|
return {}
|
|
706
703
|
|
|
707
|
-
has_all_fetch_positions = self._update_fetch_positions(timeout_ms=
|
|
704
|
+
has_all_fetch_positions = self._update_fetch_positions(timeout_ms=timer.timeout_ms)
|
|
708
705
|
|
|
709
706
|
# If data is available already, e.g. from a previous network client
|
|
710
707
|
# poll() call to commit, then just return it immediately
|
|
711
708
|
records, partial = self._fetcher.fetched_records(max_records, update_offsets=update_offsets)
|
|
709
|
+
log.debug('Fetched records: %s, %s', records, partial)
|
|
712
710
|
# Before returning the fetched records, we can send off the
|
|
713
711
|
# next round of fetches and avoid block waiting for their
|
|
714
712
|
# responses to enable pipelining while the user is handling the
|
|
715
713
|
# fetched records.
|
|
716
714
|
if not partial:
|
|
715
|
+
log.debug("Sending fetches")
|
|
717
716
|
futures = self._fetcher.send_fetches()
|
|
718
717
|
if len(futures):
|
|
719
718
|
self._client.poll(timeout_ms=0)
|
|
@@ -723,7 +722,7 @@ class KafkaConsumer(six.Iterator):
|
|
|
723
722
|
|
|
724
723
|
# We do not want to be stuck blocking in poll if we are missing some positions
|
|
725
724
|
# since the offset lookup may be backing off after a failure
|
|
726
|
-
poll_timeout_ms =
|
|
725
|
+
poll_timeout_ms = min(timer.timeout_ms, self._coordinator.time_to_next_poll() * 1000)
|
|
727
726
|
if not has_all_fetch_positions:
|
|
728
727
|
poll_timeout_ms = min(poll_timeout_ms, self.config['retry_backoff_ms'])
|
|
729
728
|
|
|
@@ -749,15 +748,14 @@ class KafkaConsumer(six.Iterator):
|
|
|
749
748
|
raise TypeError('partition must be a TopicPartition namedtuple')
|
|
750
749
|
assert self._subscription.is_assigned(partition), 'Partition is not assigned'
|
|
751
750
|
|
|
752
|
-
|
|
751
|
+
timer = Timer(timeout_ms)
|
|
753
752
|
position = self._subscription.assignment[partition].position
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
self._update_fetch_positions(timeout_ms=inner_timeout_ms())
|
|
753
|
+
while position is None:
|
|
754
|
+
# batch update fetch positions for any partitions without a valid position
|
|
755
|
+
if self._update_fetch_positions(timeout_ms=timer.timeout_ms):
|
|
758
756
|
position = self._subscription.assignment[partition].position
|
|
759
|
-
|
|
760
|
-
|
|
757
|
+
elif timer.expired:
|
|
758
|
+
return None
|
|
761
759
|
else:
|
|
762
760
|
return position.offset
|
|
763
761
|
|
kafka/coordinator/base.py
CHANGED
|
@@ -16,7 +16,7 @@ from kafka.metrics import AnonMeasurable
|
|
|
16
16
|
from kafka.metrics.stats import Avg, Count, Max, Rate
|
|
17
17
|
from kafka.protocol.find_coordinator import FindCoordinatorRequest
|
|
18
18
|
from kafka.protocol.group import HeartbeatRequest, JoinGroupRequest, LeaveGroupRequest, SyncGroupRequest, DEFAULT_GENERATION_ID, UNKNOWN_MEMBER_ID
|
|
19
|
-
from kafka.util import
|
|
19
|
+
from kafka.util import Timer
|
|
20
20
|
|
|
21
21
|
log = logging.getLogger('kafka.coordinator')
|
|
22
22
|
|
|
@@ -256,9 +256,9 @@ class BaseCoordinator(object):
|
|
|
256
256
|
timeout_ms (numeric, optional): Maximum number of milliseconds to
|
|
257
257
|
block waiting to find coordinator. Default: None.
|
|
258
258
|
|
|
259
|
-
|
|
259
|
+
Returns: True is coordinator found before timeout_ms, else False
|
|
260
260
|
"""
|
|
261
|
-
|
|
261
|
+
timer = Timer(timeout_ms)
|
|
262
262
|
with self._client._lock, self._lock:
|
|
263
263
|
while self.coordinator_unknown():
|
|
264
264
|
|
|
@@ -272,27 +272,37 @@ class BaseCoordinator(object):
|
|
|
272
272
|
else:
|
|
273
273
|
self.coordinator_id = maybe_coordinator_id
|
|
274
274
|
self._client.maybe_connect(self.coordinator_id)
|
|
275
|
-
|
|
275
|
+
if timer.expired:
|
|
276
|
+
return False
|
|
277
|
+
else:
|
|
278
|
+
continue
|
|
276
279
|
else:
|
|
277
280
|
future = self.lookup_coordinator()
|
|
278
281
|
|
|
279
|
-
self._client.poll(future=future, timeout_ms=
|
|
282
|
+
self._client.poll(future=future, timeout_ms=timer.timeout_ms)
|
|
280
283
|
|
|
281
284
|
if not future.is_done:
|
|
282
|
-
|
|
285
|
+
return False
|
|
283
286
|
|
|
284
287
|
if future.failed():
|
|
285
288
|
if future.retriable():
|
|
286
289
|
if getattr(future.exception, 'invalid_metadata', False):
|
|
287
290
|
log.debug('Requesting metadata for group coordinator request: %s', future.exception)
|
|
288
291
|
metadata_update = self._client.cluster.request_update()
|
|
289
|
-
self._client.poll(future=metadata_update, timeout_ms=
|
|
292
|
+
self._client.poll(future=metadata_update, timeout_ms=timer.timeout_ms)
|
|
290
293
|
if not metadata_update.is_done:
|
|
291
|
-
|
|
294
|
+
return False
|
|
292
295
|
else:
|
|
293
|
-
|
|
296
|
+
if timeout_ms is None or timer.timeout_ms > self.config['retry_backoff_ms']:
|
|
297
|
+
time.sleep(self.config['retry_backoff_ms'] / 1000)
|
|
298
|
+
else:
|
|
299
|
+
time.sleep(timer.timeout_ms / 1000)
|
|
294
300
|
else:
|
|
295
301
|
raise future.exception # pylint: disable-msg=raising-bad-type
|
|
302
|
+
if timer.expired:
|
|
303
|
+
return False
|
|
304
|
+
else:
|
|
305
|
+
return True
|
|
296
306
|
|
|
297
307
|
def _reset_find_coordinator_future(self, result):
|
|
298
308
|
self._find_coordinator_future = None
|
|
@@ -407,21 +417,23 @@ class BaseCoordinator(object):
|
|
|
407
417
|
timeout_ms (numeric, optional): Maximum number of milliseconds to
|
|
408
418
|
block waiting to join group. Default: None.
|
|
409
419
|
|
|
410
|
-
|
|
420
|
+
Returns: True if group initialized before timeout_ms, else False
|
|
411
421
|
"""
|
|
412
422
|
if self.config['api_version'] < (0, 9):
|
|
413
423
|
raise Errors.UnsupportedVersionError('Group Coordinator APIs require 0.9+ broker')
|
|
414
|
-
|
|
415
|
-
self.ensure_coordinator_ready(timeout_ms=
|
|
424
|
+
timer = Timer(timeout_ms)
|
|
425
|
+
if not self.ensure_coordinator_ready(timeout_ms=timer.timeout_ms):
|
|
426
|
+
return False
|
|
416
427
|
self._start_heartbeat_thread()
|
|
417
|
-
self.join_group(timeout_ms=
|
|
428
|
+
return self.join_group(timeout_ms=timer.timeout_ms)
|
|
418
429
|
|
|
419
430
|
def join_group(self, timeout_ms=None):
|
|
420
431
|
if self.config['api_version'] < (0, 9):
|
|
421
432
|
raise Errors.UnsupportedVersionError('Group Coordinator APIs require 0.9+ broker')
|
|
422
|
-
|
|
433
|
+
timer = Timer(timeout_ms)
|
|
423
434
|
while self.need_rejoin():
|
|
424
|
-
self.ensure_coordinator_ready(timeout_ms=
|
|
435
|
+
if not self.ensure_coordinator_ready(timeout_ms=timer.timeout_ms):
|
|
436
|
+
return False
|
|
425
437
|
|
|
426
438
|
# call on_join_prepare if needed. We set a flag
|
|
427
439
|
# to make sure that we do not call it a second
|
|
@@ -434,7 +446,7 @@ class BaseCoordinator(object):
|
|
|
434
446
|
if not self.rejoining:
|
|
435
447
|
self._on_join_prepare(self._generation.generation_id,
|
|
436
448
|
self._generation.member_id,
|
|
437
|
-
timeout_ms=
|
|
449
|
+
timeout_ms=timer.timeout_ms)
|
|
438
450
|
self.rejoining = True
|
|
439
451
|
|
|
440
452
|
# fence off the heartbeat thread explicitly so that it cannot
|
|
@@ -449,16 +461,19 @@ class BaseCoordinator(object):
|
|
|
449
461
|
while not self.coordinator_unknown():
|
|
450
462
|
if not self._client.in_flight_request_count(self.coordinator_id):
|
|
451
463
|
break
|
|
452
|
-
|
|
464
|
+
poll_timeout_ms = 200 if timer.timeout_ms is None or timer.timeout_ms > 200 else timer.timeout_ms
|
|
465
|
+
self._client.poll(timeout_ms=poll_timeout_ms)
|
|
466
|
+
if timer.expired:
|
|
467
|
+
return False
|
|
453
468
|
else:
|
|
454
469
|
continue
|
|
455
470
|
|
|
456
471
|
future = self._initiate_join_group()
|
|
457
|
-
self._client.poll(future=future, timeout_ms=
|
|
472
|
+
self._client.poll(future=future, timeout_ms=timer.timeout_ms)
|
|
458
473
|
if future.is_done:
|
|
459
474
|
self._reset_join_group_future()
|
|
460
475
|
else:
|
|
461
|
-
|
|
476
|
+
return False
|
|
462
477
|
|
|
463
478
|
if future.succeeded():
|
|
464
479
|
self.rejoining = False
|
|
@@ -467,6 +482,7 @@ class BaseCoordinator(object):
|
|
|
467
482
|
self._generation.member_id,
|
|
468
483
|
self._generation.protocol,
|
|
469
484
|
future.value)
|
|
485
|
+
return True
|
|
470
486
|
else:
|
|
471
487
|
exception = future.exception
|
|
472
488
|
if isinstance(exception, (Errors.UnknownMemberIdError,
|
|
@@ -476,7 +492,13 @@ class BaseCoordinator(object):
|
|
|
476
492
|
continue
|
|
477
493
|
elif not future.retriable():
|
|
478
494
|
raise exception # pylint: disable-msg=raising-bad-type
|
|
479
|
-
|
|
495
|
+
elif timer.expired:
|
|
496
|
+
return False
|
|
497
|
+
else:
|
|
498
|
+
if timer.timeout_ms is None or timer.timeout_ms > self.config['retry_backoff_ms']:
|
|
499
|
+
time.sleep(self.config['retry_backoff_ms'] / 1000)
|
|
500
|
+
else:
|
|
501
|
+
time.sleep(timer.timeout_ms / 1000)
|
|
480
502
|
|
|
481
503
|
def _send_join_group_request(self):
|
|
482
504
|
"""Join the group and return the assignment for the next generation.
|
kafka/coordinator/consumer.py
CHANGED
|
@@ -19,7 +19,7 @@ from kafka.metrics import AnonMeasurable
|
|
|
19
19
|
from kafka.metrics.stats import Avg, Count, Max, Rate
|
|
20
20
|
from kafka.protocol.commit import OffsetCommitRequest, OffsetFetchRequest
|
|
21
21
|
from kafka.structs import OffsetAndMetadata, TopicPartition
|
|
22
|
-
from kafka.util import
|
|
22
|
+
from kafka.util import Timer, WeakMethod
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
log = logging.getLogger(__name__)
|
|
@@ -95,6 +95,7 @@ class ConsumerCoordinator(BaseCoordinator):
|
|
|
95
95
|
self.auto_commit_interval = self.config['auto_commit_interval_ms'] / 1000
|
|
96
96
|
self.next_auto_commit_deadline = None
|
|
97
97
|
self.completed_offset_commits = collections.deque()
|
|
98
|
+
self._offset_fetch_futures = dict()
|
|
98
99
|
|
|
99
100
|
if self.config['default_offset_commit_callback'] is None:
|
|
100
101
|
self.config['default_offset_commit_callback'] = self._default_offset_commit_callback
|
|
@@ -269,10 +270,11 @@ class ConsumerCoordinator(BaseCoordinator):
|
|
|
269
270
|
if self.group_id is None:
|
|
270
271
|
return True
|
|
271
272
|
|
|
272
|
-
|
|
273
|
+
timer = Timer(timeout_ms)
|
|
273
274
|
try:
|
|
274
275
|
self._invoke_completed_offset_commit_callbacks()
|
|
275
|
-
self.ensure_coordinator_ready(timeout_ms=
|
|
276
|
+
if not self.ensure_coordinator_ready(timeout_ms=timer.timeout_ms):
|
|
277
|
+
return False
|
|
276
278
|
|
|
277
279
|
if self.config['api_version'] >= (0, 9) and self._subscription.partitions_auto_assigned():
|
|
278
280
|
if self.need_rejoin():
|
|
@@ -289,9 +291,12 @@ class ConsumerCoordinator(BaseCoordinator):
|
|
|
289
291
|
# description of the problem.
|
|
290
292
|
if self._subscription.subscribed_pattern:
|
|
291
293
|
metadata_update = self._client.cluster.request_update()
|
|
292
|
-
self._client.poll(future=metadata_update, timeout_ms=
|
|
294
|
+
self._client.poll(future=metadata_update, timeout_ms=timer.timeout_ms)
|
|
295
|
+
if not metadata_update.is_done:
|
|
296
|
+
return False
|
|
293
297
|
|
|
294
|
-
self.ensure_active_group(timeout_ms=
|
|
298
|
+
if not self.ensure_active_group(timeout_ms=timer.timeout_ms):
|
|
299
|
+
return False
|
|
295
300
|
|
|
296
301
|
self.poll_heartbeat()
|
|
297
302
|
|
|
@@ -395,10 +400,14 @@ class ConsumerCoordinator(BaseCoordinator):
|
|
|
395
400
|
def refresh_committed_offsets_if_needed(self, timeout_ms=None):
|
|
396
401
|
"""Fetch committed offsets for assigned partitions."""
|
|
397
402
|
missing_fetch_positions = set(self._subscription.missing_fetch_positions())
|
|
398
|
-
|
|
403
|
+
try:
|
|
404
|
+
offsets = self.fetch_committed_offsets(missing_fetch_positions, timeout_ms=timeout_ms)
|
|
405
|
+
except Errors.KafkaTimeoutError:
|
|
406
|
+
return False
|
|
399
407
|
for partition, offset in six.iteritems(offsets):
|
|
400
|
-
log.debug("Setting offset for partition %s to the committed offset %s", partition, offset.offset)
|
|
408
|
+
log.debug("Setting offset for partition %s to the committed offset %s", partition, offset.offset)
|
|
401
409
|
self._subscription.seek(partition, offset.offset)
|
|
410
|
+
return True
|
|
402
411
|
|
|
403
412
|
def fetch_committed_offsets(self, partitions, timeout_ms=None):
|
|
404
413
|
"""Fetch the current committed offsets for specified partitions
|
|
@@ -415,24 +424,35 @@ class ConsumerCoordinator(BaseCoordinator):
|
|
|
415
424
|
if not partitions:
|
|
416
425
|
return {}
|
|
417
426
|
|
|
418
|
-
|
|
427
|
+
future_key = frozenset(partitions)
|
|
428
|
+
timer = Timer(timeout_ms)
|
|
419
429
|
while True:
|
|
420
|
-
self.ensure_coordinator_ready(timeout_ms=
|
|
430
|
+
self.ensure_coordinator_ready(timeout_ms=timer.timeout_ms)
|
|
421
431
|
|
|
422
432
|
# contact coordinator to fetch committed offsets
|
|
423
|
-
|
|
424
|
-
|
|
433
|
+
if future_key in self._offset_fetch_futures:
|
|
434
|
+
future = self._offset_fetch_futures[future_key]
|
|
435
|
+
else:
|
|
436
|
+
future = self._send_offset_fetch_request(partitions)
|
|
437
|
+
self._offset_fetch_futures[future_key] = future
|
|
425
438
|
|
|
426
|
-
|
|
427
|
-
raise Errors.KafkaTimeoutError()
|
|
439
|
+
self._client.poll(future=future, timeout_ms=timer.timeout_ms)
|
|
428
440
|
|
|
429
|
-
if future.
|
|
430
|
-
|
|
441
|
+
if future.is_done:
|
|
442
|
+
del self._offset_fetch_futures[future_key]
|
|
431
443
|
|
|
432
|
-
|
|
433
|
-
|
|
444
|
+
if future.succeeded():
|
|
445
|
+
return future.value
|
|
434
446
|
|
|
435
|
-
|
|
447
|
+
elif not future.retriable():
|
|
448
|
+
raise future.exception # pylint: disable-msg=raising-bad-type
|
|
449
|
+
|
|
450
|
+
# future failed but is retriable, or is not done yet
|
|
451
|
+
if timer.timeout_ms is None or timer.timeout_ms > self.config['retry_backoff_ms']:
|
|
452
|
+
time.sleep(self.config['retry_backoff_ms'] / 1000)
|
|
453
|
+
else:
|
|
454
|
+
time.sleep(timer.timeout_ms / 1000)
|
|
455
|
+
timer.maybe_raise()
|
|
436
456
|
|
|
437
457
|
def close(self, autocommit=True, timeout_ms=None):
|
|
438
458
|
"""Close the coordinator, leave the current group,
|
|
@@ -523,23 +543,26 @@ class ConsumerCoordinator(BaseCoordinator):
|
|
|
523
543
|
if not offsets:
|
|
524
544
|
return
|
|
525
545
|
|
|
526
|
-
|
|
546
|
+
timer = Timer(timeout_ms)
|
|
527
547
|
while True:
|
|
528
|
-
self.ensure_coordinator_ready(timeout_ms=
|
|
548
|
+
self.ensure_coordinator_ready(timeout_ms=timer.timeout_ms)
|
|
529
549
|
|
|
530
550
|
future = self._send_offset_commit_request(offsets)
|
|
531
|
-
self._client.poll(future=future, timeout_ms=
|
|
532
|
-
|
|
533
|
-
if not future.is_done:
|
|
534
|
-
raise Errors.KafkaTimeoutError()
|
|
551
|
+
self._client.poll(future=future, timeout_ms=timer.timeout_ms)
|
|
535
552
|
|
|
536
|
-
if future.
|
|
537
|
-
|
|
553
|
+
if future.is_done:
|
|
554
|
+
if future.succeeded():
|
|
555
|
+
return future.value
|
|
538
556
|
|
|
539
|
-
|
|
540
|
-
|
|
557
|
+
elif not future.retriable():
|
|
558
|
+
raise future.exception # pylint: disable-msg=raising-bad-type
|
|
541
559
|
|
|
542
|
-
|
|
560
|
+
# future failed but is retriable, or it is still pending
|
|
561
|
+
if timer.timeout_ms is None or timer.timeout_ms > self.config['retry_backoff_ms']:
|
|
562
|
+
time.sleep(self.config['retry_backoff_ms'] / 1000)
|
|
563
|
+
else:
|
|
564
|
+
time.sleep(timer.timeout_ms / 1000)
|
|
565
|
+
timer.maybe_raise()
|
|
543
566
|
|
|
544
567
|
def _maybe_auto_commit_offsets_sync(self, timeout_ms=None):
|
|
545
568
|
if self.config['enable_auto_commit']:
|
|
@@ -591,18 +614,19 @@ class ConsumerCoordinator(BaseCoordinator):
|
|
|
591
614
|
for tp, offset in six.iteritems(offsets):
|
|
592
615
|
offset_data[tp.topic][tp.partition] = offset
|
|
593
616
|
|
|
594
|
-
|
|
595
|
-
|
|
617
|
+
version = self._client.api_version(OffsetCommitRequest, max_version=6)
|
|
618
|
+
if version > 1 and self._subscription.partitions_auto_assigned():
|
|
619
|
+
generation = self.generation()
|
|
596
620
|
else:
|
|
597
621
|
generation = Generation.NO_GENERATION
|
|
598
622
|
|
|
599
623
|
# if the generation is None, we are not part of an active group
|
|
600
624
|
# (and we expect to be). The only thing we can do is fail the commit
|
|
601
625
|
# and let the user rejoin the group in poll()
|
|
602
|
-
if
|
|
603
|
-
|
|
626
|
+
if generation is None:
|
|
627
|
+
log.info("Failing OffsetCommit request since the consumer is not part of an active group")
|
|
628
|
+
return Future().failure(Errors.CommitFailedError('Group rebalance in progress'))
|
|
604
629
|
|
|
605
|
-
version = self._client.api_version(OffsetCommitRequest, max_version=6)
|
|
606
630
|
if version == 0:
|
|
607
631
|
request = OffsetCommitRequest[version](
|
|
608
632
|
self.group_id,
|
|
@@ -724,13 +748,22 @@ class ConsumerCoordinator(BaseCoordinator):
|
|
|
724
748
|
self.coordinator_dead(error_type())
|
|
725
749
|
future.failure(error_type(self.group_id))
|
|
726
750
|
return
|
|
751
|
+
elif error_type is Errors.RebalanceInProgressError:
|
|
752
|
+
# Consumer never tries to commit offset in between join-group and sync-group,
|
|
753
|
+
# and hence on broker-side it is not expected to see a commit offset request
|
|
754
|
+
# during CompletingRebalance phase; if it ever happens then broker would return
|
|
755
|
+
# this error. In this case we should just treat as a fatal CommitFailed exception.
|
|
756
|
+
# However, we do not need to reset generations and just request re-join, such that
|
|
757
|
+
# if the caller decides to proceed and poll, it would still try to proceed and re-join normally.
|
|
758
|
+
self.request_rejoin()
|
|
759
|
+
future.failure(Errors.CommitFailedError('Group rebalance in progress'))
|
|
760
|
+
return
|
|
727
761
|
elif error_type in (Errors.UnknownMemberIdError,
|
|
728
|
-
Errors.IllegalGenerationError
|
|
729
|
-
|
|
730
|
-
# need to re-join group
|
|
762
|
+
Errors.IllegalGenerationError):
|
|
763
|
+
# need reset generation and re-join group
|
|
731
764
|
error = error_type(self.group_id)
|
|
732
|
-
log.
|
|
733
|
-
|
|
765
|
+
log.warning("OffsetCommit for group %s failed: %s",
|
|
766
|
+
self.group_id, error)
|
|
734
767
|
self.reset_generation()
|
|
735
768
|
future.failure(Errors.CommitFailedError())
|
|
736
769
|
return
|
kafka/errors.py
CHANGED
|
@@ -21,18 +21,18 @@ class Cancelled(KafkaError):
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class CommitFailedError(KafkaError):
|
|
24
|
-
def __init__(self, *args
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
def __init__(self, *args):
|
|
25
|
+
if not args:
|
|
26
|
+
args = ("Commit cannot be completed since the group has already"
|
|
27
|
+
" rebalanced and assigned the partitions to another member."
|
|
28
|
+
" This means that the time between subsequent calls to poll()"
|
|
29
|
+
" was longer than the configured max_poll_interval_ms, which"
|
|
30
|
+
" typically implies that the poll loop is spending too much"
|
|
31
|
+
" time message processing. You can address this either by"
|
|
32
|
+
" increasing the rebalance timeout with max_poll_interval_ms,"
|
|
33
|
+
" or by reducing the maximum size of batches returned in poll()"
|
|
34
|
+
" with max_poll_records.",)
|
|
35
|
+
super(CommitFailedError, self).__init__(*args)
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
class IllegalArgumentError(KafkaError):
|
kafka/producer/kafka.py
CHANGED
|
@@ -5,7 +5,6 @@ import copy
|
|
|
5
5
|
import logging
|
|
6
6
|
import socket
|
|
7
7
|
import threading
|
|
8
|
-
import time
|
|
9
8
|
import warnings
|
|
10
9
|
import weakref
|
|
11
10
|
|
|
@@ -24,7 +23,7 @@ from kafka.record.default_records import DefaultRecordBatchBuilder
|
|
|
24
23
|
from kafka.record.legacy_records import LegacyRecordBatchBuilder
|
|
25
24
|
from kafka.serializer import Serializer
|
|
26
25
|
from kafka.structs import TopicPartition
|
|
27
|
-
from kafka.util import ensure_valid_topic_name
|
|
26
|
+
from kafka.util import Timer, ensure_valid_topic_name
|
|
28
27
|
|
|
29
28
|
|
|
30
29
|
log = logging.getLogger(__name__)
|
|
@@ -664,8 +663,7 @@ class KafkaProducer(object):
|
|
|
664
663
|
|
|
665
664
|
def partitions_for(self, topic):
|
|
666
665
|
"""Returns set of all known partitions for the topic."""
|
|
667
|
-
|
|
668
|
-
return self._wait_on_metadata(topic, max_wait)
|
|
666
|
+
return self._wait_on_metadata(topic, self.config['max_block_ms'])
|
|
669
667
|
|
|
670
668
|
@classmethod
|
|
671
669
|
def max_usable_produce_magic(cls, api_version):
|
|
@@ -835,14 +833,11 @@ class KafkaProducer(object):
|
|
|
835
833
|
assert not (value is None and key is None), 'Need at least one: key or value'
|
|
836
834
|
ensure_valid_topic_name(topic)
|
|
837
835
|
key_bytes = value_bytes = None
|
|
836
|
+
timer = Timer(self.config['max_block_ms'], "Failed to assign partition for message in max_block_ms.")
|
|
838
837
|
try:
|
|
839
838
|
assigned_partition = None
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
timeout = self.config['max_block_ms'] / 1000
|
|
843
|
-
while assigned_partition is None and elapsed < timeout:
|
|
844
|
-
elapsed = time.time() - begin
|
|
845
|
-
self._wait_on_metadata(topic, timeout - elapsed)
|
|
839
|
+
while assigned_partition is None and not timer.expired:
|
|
840
|
+
self._wait_on_metadata(topic, timer.timeout_ms)
|
|
846
841
|
|
|
847
842
|
key_bytes = self._serialize(
|
|
848
843
|
self.config['key_serializer'],
|
|
@@ -856,7 +851,7 @@ class KafkaProducer(object):
|
|
|
856
851
|
assigned_partition = self._partition(topic, partition, key, value,
|
|
857
852
|
key_bytes, value_bytes)
|
|
858
853
|
if assigned_partition is None:
|
|
859
|
-
raise Errors.KafkaTimeoutError("Failed to assign partition for message after %s secs." %
|
|
854
|
+
raise Errors.KafkaTimeoutError("Failed to assign partition for message after %s secs." % timer.elapsed_ms / 1000)
|
|
860
855
|
else:
|
|
861
856
|
partition = assigned_partition
|
|
862
857
|
|
|
@@ -931,7 +926,7 @@ class KafkaProducer(object):
|
|
|
931
926
|
" the maximum request size you have configured with the"
|
|
932
927
|
" max_request_size configuration" % (size,))
|
|
933
928
|
|
|
934
|
-
def _wait_on_metadata(self, topic,
|
|
929
|
+
def _wait_on_metadata(self, topic, max_wait_ms):
|
|
935
930
|
"""
|
|
936
931
|
Wait for cluster metadata including partitions for the given topic to
|
|
937
932
|
be available.
|
|
@@ -949,36 +944,29 @@ class KafkaProducer(object):
|
|
|
949
944
|
"""
|
|
950
945
|
# add topic to metadata topic list if it is not there already.
|
|
951
946
|
self._sender.add_topic(topic)
|
|
952
|
-
|
|
953
|
-
elapsed = 0.0
|
|
947
|
+
timer = Timer(max_wait_ms, "Failed to update metadata after %.1f secs." % (max_wait_ms * 1000,))
|
|
954
948
|
metadata_event = None
|
|
955
949
|
while True:
|
|
956
950
|
partitions = self._metadata.partitions_for_topic(topic)
|
|
957
951
|
if partitions is not None:
|
|
958
952
|
return partitions
|
|
959
|
-
|
|
960
|
-
if elapsed >= max_wait:
|
|
961
|
-
raise Errors.KafkaTimeoutError(
|
|
962
|
-
"Failed to update metadata after %.1f secs." % (max_wait,))
|
|
963
|
-
|
|
953
|
+
timer.maybe_raise()
|
|
964
954
|
if not metadata_event:
|
|
965
955
|
metadata_event = threading.Event()
|
|
966
956
|
|
|
967
957
|
log.debug("%s: Requesting metadata update for topic %s", str(self), topic)
|
|
968
|
-
|
|
969
958
|
metadata_event.clear()
|
|
970
959
|
future = self._metadata.request_update()
|
|
971
960
|
future.add_both(lambda e, *args: e.set(), metadata_event)
|
|
972
961
|
self._sender.wakeup()
|
|
973
|
-
metadata_event.wait(
|
|
962
|
+
metadata_event.wait(timer.timeout_ms / 1000)
|
|
974
963
|
if not metadata_event.is_set():
|
|
975
964
|
raise Errors.KafkaTimeoutError(
|
|
976
|
-
"Failed to update metadata after %.1f secs." % (
|
|
965
|
+
"Failed to update metadata after %.1f secs." % (max_wait_ms * 1000,))
|
|
977
966
|
elif topic in self._metadata.unauthorized_topics:
|
|
978
967
|
raise Errors.TopicAuthorizationFailedError(set([topic]))
|
|
979
968
|
else:
|
|
980
|
-
|
|
981
|
-
log.debug("%s: _wait_on_metadata woke after %s secs.", str(self), elapsed)
|
|
969
|
+
log.debug("%s: _wait_on_metadata woke after %s secs.", str(self), timer.elapsed_ms / 1000)
|
|
982
970
|
|
|
983
971
|
def _serialize(self, f, topic, data):
|
|
984
972
|
if not f:
|
kafka/util.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from __future__ import absolute_import
|
|
1
|
+
from __future__ import absolute_import, division
|
|
2
2
|
|
|
3
3
|
import binascii
|
|
4
4
|
import re
|
|
@@ -25,24 +25,44 @@ else:
|
|
|
25
25
|
from binascii import crc32 # noqa: F401
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
28
|
+
class Timer:
|
|
29
|
+
__slots__ = ('_start_at', '_expire_at', '_timeout_ms', '_error_message')
|
|
30
|
+
|
|
31
|
+
def __init__(self, timeout_ms, error_message=None, start_at=None):
|
|
32
|
+
self._timeout_ms = timeout_ms
|
|
33
|
+
self._start_at = start_at or time.time()
|
|
34
|
+
if timeout_ms is not None:
|
|
35
|
+
self._expire_at = self._start_at + timeout_ms / 1000
|
|
36
|
+
else:
|
|
37
|
+
self._expire_at = float('inf')
|
|
38
|
+
self._error_message = error_message
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def expired(self):
|
|
42
|
+
return time.time() >= self._expire_at
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def timeout_ms(self):
|
|
46
|
+
if self._timeout_ms is None:
|
|
47
|
+
return None
|
|
48
|
+
elif self._expire_at == float('inf'):
|
|
49
|
+
return float('inf')
|
|
50
|
+
remaining = self._expire_at - time.time()
|
|
51
|
+
if remaining < 0:
|
|
52
|
+
return 0
|
|
53
|
+
else:
|
|
54
|
+
return int(remaining * 1000)
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def elapsed_ms(self):
|
|
58
|
+
return int(1000 * (time.time() - self._start_at))
|
|
59
|
+
|
|
60
|
+
def maybe_raise(self):
|
|
61
|
+
if self.expired:
|
|
62
|
+
raise KafkaTimeoutError(self._error_message)
|
|
63
|
+
|
|
64
|
+
def __str__(self):
|
|
65
|
+
return "Timer(%s ms remaining)" % (self.timeout_ms)
|
|
46
66
|
|
|
47
67
|
# Taken from: https://github.com/apache/kafka/blob/39eb31feaeebfb184d98cc5d94da9148c2319d81/clients/src/main/java/org/apache/kafka/common/internals/Topic.java#L29
|
|
48
68
|
TOPIC_MAX_LENGTH = 249
|
kafka/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = '2.2.
|
|
1
|
+
__version__ = '2.2.4'
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
kafka/__init__.py,sha256=4dvHKZAxmD_4tfJ5wGcRV2X78vPcm8vsUoqceULevjA,1077
|
|
2
|
-
kafka/client_async.py,sha256=
|
|
2
|
+
kafka/client_async.py,sha256=R8q_rRpG3RrYrRmcZo7XgO2oSdpLJATNcq8w-1vIJ_8,56878
|
|
3
3
|
kafka/cluster.py,sha256=N3_Al4We4ZhWzz6lVHy6SfqwDZfQy73iV7Qg4g4nxRs,16745
|
|
4
4
|
kafka/codec.py,sha256=8NZpnehzNrhSBIjzbPVSvyFbSeLAqEntE7BfVHu-_9I,10036
|
|
5
5
|
kafka/conn.py,sha256=pDmzcn-m8oiFdvYh-97qbRLEBXh0sSl9nT74VIIRuEE,69472
|
|
6
|
-
kafka/errors.py,sha256=
|
|
6
|
+
kafka/errors.py,sha256=VygO7AYZvbb52wVgjxuXz-6S2W3vNzzDstF5FNP8Bvk,33829
|
|
7
7
|
kafka/future.py,sha256=ZQStbfUYIPJRrgMfAWxxjrIRVxsw4WCtSR0J0bkyGno,2847
|
|
8
8
|
kafka/socks5_wrapper.py,sha256=6woOaCTJXJ5e89_zdyW5BjOpyE4rCbYFH-kd-FeuPuk,9827
|
|
9
9
|
kafka/structs.py,sha256=SJGzmLdV21jZyQ7247k0WFy16UiusgTHK3I-e4qzI-E,3058
|
|
10
|
-
kafka/util.py,sha256=
|
|
11
|
-
kafka/version.py,sha256=
|
|
10
|
+
kafka/util.py,sha256=EnzCJuRkQ6Kh2lIdNwFKvT4PddkZ5bzop4ooGGIhe5g,4366
|
|
11
|
+
kafka/version.py,sha256=fHmc2ETGBC5aQYYEdjwwhCQpc1iDi4YoXAxIb24VljI,22
|
|
12
12
|
kafka/admin/__init__.py,sha256=S_XxqyyV480_yXhttK79XZqNAmZyXRjspd3SoqYykE8,720
|
|
13
13
|
kafka/admin/acl_resource.py,sha256=ak_dUsSni4SyP0ORbSKenZpwTy0Ykxq3FSt_9XgLR8k,8265
|
|
14
14
|
kafka/admin/client.py,sha256=RabA8l8Im3iBEXgPVkiofNW6QyeatQHaymBWFZ8Sxkw,78929
|
|
@@ -23,12 +23,12 @@ kafka/benchmarks/record_batch_compose.py,sha256=CnUreNg1lUT0Qx9enmSr-THmBl9PjVMf
|
|
|
23
23
|
kafka/benchmarks/record_batch_read.py,sha256=vlFaWU2YWI379n_2M8qieb_S2uHUWKV0NquEYy5b-Ho,2184
|
|
24
24
|
kafka/benchmarks/varint_speed.py,sha256=s4CuvKgDZL-_zna5E3vM8RgHjhXuW6pcaO1z1WYZ_0Y,12585
|
|
25
25
|
kafka/consumer/__init__.py,sha256=NDdvtyuJgFyQZahqL9i5sYXGP6rOMIXWwHQEaZ1fCcs,122
|
|
26
|
-
kafka/consumer/fetcher.py,sha256=
|
|
27
|
-
kafka/consumer/group.py,sha256=
|
|
26
|
+
kafka/consumer/fetcher.py,sha256=iwYhWotaEQ55oXTzGKPUOYxvC_6FcoIks_ZqL-gu3DE,68855
|
|
27
|
+
kafka/consumer/group.py,sha256=xmEpVMPJbCAk9__pdAOMswh8I-Ujj5hBax_hPZHZb_s,58758
|
|
28
28
|
kafka/consumer/subscription_state.py,sha256=f_qJQMhTWQnUd_7lPj43gsagWSKGEmP4jpnEwA6s1Ec,23661
|
|
29
29
|
kafka/coordinator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
|
-
kafka/coordinator/base.py,sha256=
|
|
31
|
-
kafka/coordinator/consumer.py,sha256=
|
|
30
|
+
kafka/coordinator/base.py,sha256=1FxVQ5QR854Ysr8qLW8j2k4PrFvaB-GsMAdq1TKQVG4,51362
|
|
31
|
+
kafka/coordinator/consumer.py,sha256=IJWWt4E6E7JZZGKtGgPtud9V3eqs0js6EaosS3bxffE,44766
|
|
32
32
|
kafka/coordinator/heartbeat.py,sha256=WJqZGnXHG7TTq1Is3D0mKDis-bBwWVZlSgQiUoZv1jU,2304
|
|
33
33
|
kafka/coordinator/protocol.py,sha256=wTaIOnUVbj0CKXZ82FktZo-zMRvOCk3hdQAoHJ62e3I,1041
|
|
34
34
|
kafka/coordinator/assignors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -67,7 +67,7 @@ kafka/partitioner/__init__.py,sha256=Fks3C5_kokVWYw1Ad5wv0sVVzaaBtOejL-2bIL1yRII
|
|
|
67
67
|
kafka/partitioner/default.py,sha256=tW-RC1PWIPRDEbeEAaPTLn-00oiZnXoVouEk9AnYE4w,2879
|
|
68
68
|
kafka/producer/__init__.py,sha256=i3Wxih0NHjmqCkRNE54ial8fBp9siqabUE6ZGyL6oX8,122
|
|
69
69
|
kafka/producer/future.py,sha256=UC3-g9QlgVFmbitrtMXVpeP0Pbvr7xl2kcw6bAehKG8,2983
|
|
70
|
-
kafka/producer/kafka.py,sha256=
|
|
70
|
+
kafka/producer/kafka.py,sha256=rzsAoB4ser889nRCtILqGqzWI7jREGV9HPngimCWJPE,53211
|
|
71
71
|
kafka/producer/record_accumulator.py,sha256=a_mdSATxl-3dVT2rVFh1gTwAv0wUzNbGwVXScwWJ5AE,28072
|
|
72
72
|
kafka/producer/sender.py,sha256=2EeA3c7po89F2BLTPjex8-MFKzrCdbXAPvHHDa0SOec,37690
|
|
73
73
|
kafka/producer/transaction_manager.py,sha256=HNfJNZwNfJtYdftn9SeaDfi7I5MKk0LD3sK64inuPt0,41537
|
|
@@ -120,7 +120,7 @@ kafka/vendor/enum34.py,sha256=-u-lxAiJMt6ru4Do7NUDY9OpeWkYJMksb2xengJawFE,31204
|
|
|
120
120
|
kafka/vendor/selectors34.py,sha256=gxejLO4eXf8mRSGXaQiknPig3GdX1rtsZiYOQJVuAy8,20594
|
|
121
121
|
kafka/vendor/six.py,sha256=lLBa9_HrANP5BMZ7twEzg1M3wofwPmXyptuWmHX0brY,34826
|
|
122
122
|
kafka/vendor/socketpair.py,sha256=Fi3PoY1Okkppab720wFk1BhHXyjcw7hi5DwhqrYZH2Y,2737
|
|
123
|
-
kafka_python-2.2.
|
|
124
|
-
kafka_python-2.2.
|
|
125
|
-
kafka_python-2.2.
|
|
126
|
-
kafka_python-2.2.
|
|
123
|
+
kafka_python-2.2.4.dist-info/METADATA,sha256=FZ5evD2mf0bnJwo3vWAnOFNhN8xQMLXs94J8wCNnm3A,9951
|
|
124
|
+
kafka_python-2.2.4.dist-info/WHEEL,sha256=KsLc7-ImW3kO10_MVVAJ6KE49o7_KqpEzIMxFX-6COY,109
|
|
125
|
+
kafka_python-2.2.4.dist-info/top_level.txt,sha256=IivJz7l5WHdLNDT6RIiVAlhjQzYRwGqBBmKHZ7WjPeM,6
|
|
126
|
+
kafka_python-2.2.4.dist-info/RECORD,,
|
|
File without changes
|