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 timeout_ms_fn
19
+ from kafka .util import Timer
20
20
21
21
log = logging .getLogger ('kafka.coordinator' )
22
22
@@ -256,9 +256,9 @@ def ensure_coordinator_ready(self, timeout_ms=None):
256
256
timeout_ms (numeric, optional): Maximum number of milliseconds to
257
257
block waiting to find coordinator. Default: None.
258
258
259
- Raises: KafkaTimeoutError if timeout_ms is not None
259
+ Returns: True is coordinator found before timeout_ms, else False
260
260
"""
261
- inner_timeout_ms = timeout_ms_fn (timeout_ms , 'Timeout attempting to find group coordinator' )
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 @@ def ensure_coordinator_ready(self, timeout_ms=None):
272
272
else :
273
273
self .coordinator_id = maybe_coordinator_id
274
274
self ._client .maybe_connect (self .coordinator_id )
275
- continue
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 = inner_timeout_ms () )
282
+ self ._client .poll (future = future , timeout_ms = timer . timeout_ms )
280
283
281
284
if not future .is_done :
282
- raise Errors . KafkaTimeoutError ()
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 = inner_timeout_ms () )
292
+ self ._client .poll (future = metadata_update , timeout_ms = timer . timeout_ms )
290
293
if not metadata_update .is_done :
291
- raise Errors . KafkaTimeoutError ()
294
+ return False
292
295
else :
293
- time .sleep (inner_timeout_ms (self .config ['retry_backoff_ms' ]) / 1000 )
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 @@ def ensure_active_group(self, timeout_ms=None):
407
417
timeout_ms (numeric, optional): Maximum number of milliseconds to
408
418
block waiting to join group. Default: None.
409
419
410
- Raises: KafkaTimeoutError if timeout_ms is not None
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
- inner_timeout_ms = timeout_ms_fn (timeout_ms , 'Timeout attempting to join consumer group' )
415
- self .ensure_coordinator_ready (timeout_ms = inner_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 = inner_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
- inner_timeout_ms = timeout_ms_fn (timeout_ms , 'Timeout attempting to join consumer group' )
433
+ timer = Timer (timeout_ms )
423
434
while self .need_rejoin ():
424
- self .ensure_coordinator_ready (timeout_ms = inner_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 @@ def join_group(self, timeout_ms=None):
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 = inner_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 @@ def join_group(self, timeout_ms=None):
449
461
while not self .coordinator_unknown ():
450
462
if not self ._client .in_flight_request_count (self .coordinator_id ):
451
463
break
452
- self ._client .poll (timeout_ms = inner_timeout_ms (200 ))
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 = inner_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
- raise Errors . KafkaTimeoutError ()
476
+ return False
462
477
463
478
if future .succeeded ():
464
479
self .rejoining = False
@@ -467,6 +482,7 @@ def join_group(self, timeout_ms=None):
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 @@ def join_group(self, timeout_ms=None):
476
492
continue
477
493
elif not future .retriable ():
478
494
raise exception # pylint: disable-msg=raising-bad-type
479
- time .sleep (inner_timeout_ms (self .config ['retry_backoff_ms' ]) / 1000 )
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.
0 commit comments