@@ -234,10 +234,25 @@ def coordinator(self):
234
234
else :
235
235
return self .coordinator_id
236
236
237
- def ensure_coordinator_ready (self ):
238
- """Block until the coordinator for this group is known
239
- (and we have an active connection -- java client uses unsent queue).
237
+ def ensure_coordinator_ready (self , timeout_ms = None ):
238
+ """Block until the coordinator for this group is known.
239
+
240
+ Keyword Arguments:
241
+ timeout_ms (numeric, optional): Maximum number of milliseconds to
242
+ block waiting to find coordinator. Default: None.
243
+
244
+ Raises: KafkaTimeoutError if timeout_ms is not None
240
245
"""
246
+ elapsed = 0.0 # noqa: F841
247
+ begin = time .time ()
248
+ def inner_timeout_ms ():
249
+ if timeout_ms is None :
250
+ return None
251
+ elapsed = (time .time () - begin ) * 1000
252
+ if elapsed >= timeout_ms :
253
+ raise Errors .KafkaTimeoutError ('Timeout attempting to find coordinator' )
254
+ return max (0 , timeout_ms - elapsed )
255
+
241
256
with self ._client ._lock , self ._lock :
242
257
while self .coordinator_unknown ():
243
258
@@ -251,16 +266,16 @@ def ensure_coordinator_ready(self):
251
266
continue
252
267
253
268
future = self .lookup_coordinator ()
254
- self ._client .poll (future = future )
269
+ self ._client .poll (future = future , timeout_ms = inner_timeout_ms () )
255
270
256
271
if future .failed ():
257
272
if future .retriable ():
258
273
if getattr (future .exception , 'invalid_metadata' , False ):
259
274
log .debug ('Requesting metadata for group coordinator request: %s' , future .exception )
260
275
metadata_update = self ._client .cluster .request_update ()
261
- self ._client .poll (future = metadata_update )
276
+ self ._client .poll (future = metadata_update , timeout_ms = inner_timeout_ms () )
262
277
else :
263
- time .sleep (self .config ['retry_backoff_ms' ] / 1000 )
278
+ time .sleep (min ( inner_timeout_ms (), self .config ['retry_backoff_ms' ]) / 1000 )
264
279
else :
265
280
raise future .exception # pylint: disable-msg=raising-bad-type
266
281
@@ -339,14 +354,31 @@ def _handle_join_failure(self, _):
339
354
with self ._lock :
340
355
self .state = MemberState .UNJOINED
341
356
342
- def ensure_active_group (self ):
343
- """Ensure that the group is active (i.e. joined and synced)"""
357
+ def ensure_active_group (self , timeout_ms = None ):
358
+ """Ensure that the group is active (i.e. joined and synced)
359
+
360
+ Keyword Arguments:
361
+ timeout_ms (numeric, optional): Maximum number of milliseconds to
362
+ block waiting to join group. Default: None.
363
+
364
+ Raises: KafkaTimeoutError if timeout_ms is not None
365
+ """
344
366
with self ._client ._lock , self ._lock :
345
367
if self ._heartbeat_thread is None :
346
368
self ._start_heartbeat_thread ()
347
369
370
+ elapsed = 0.0 # noqa: F841
371
+ begin = time .time ()
372
+ def inner_timeout_ms ():
373
+ if timeout_ms is None :
374
+ return None
375
+ elapsed = (time .time () - begin ) * 1000
376
+ if elapsed >= timeout_ms :
377
+ raise Errors .KafkaTimeoutError ()
378
+ return max (0 , timeout_ms - elapsed )
379
+
348
380
while self .need_rejoin () or self ._rejoin_incomplete ():
349
- self .ensure_coordinator_ready ()
381
+ self .ensure_coordinator_ready (timeout_ms = inner_timeout_ms () )
350
382
351
383
# call on_join_prepare if needed. We set a flag
352
384
# to make sure that we do not call it a second
@@ -367,7 +399,7 @@ def ensure_active_group(self):
367
399
while not self .coordinator_unknown ():
368
400
if not self ._client .in_flight_request_count (self .coordinator_id ):
369
401
break
370
- self ._client .poll (timeout_ms = 200 )
402
+ self ._client .poll (timeout_ms = min ( 200 , inner_timeout_ms ()) )
371
403
else :
372
404
continue
373
405
@@ -400,7 +432,7 @@ def ensure_active_group(self):
400
432
else :
401
433
future = self .join_future
402
434
403
- self ._client .poll (future = future )
435
+ self ._client .poll (future = future , timeout_ms = inner_timeout_ms () )
404
436
405
437
if future .succeeded ():
406
438
self ._on_join_complete (self ._generation .generation_id ,
@@ -419,7 +451,7 @@ def ensure_active_group(self):
419
451
continue
420
452
elif not future .retriable ():
421
453
raise exception # pylint: disable-msg=raising-bad-type
422
- time .sleep (self .config ['retry_backoff_ms' ] / 1000 )
454
+ time .sleep (min ( inner_timeout_ms (), self .config ['retry_backoff_ms' ]) / 1000 )
423
455
424
456
def _rejoin_incomplete (self ):
425
457
return self .join_future is not None
0 commit comments