@@ -33,6 +33,16 @@ def __init__(self, generation_id, member_id, protocol):
33
33
self .member_id = member_id
34
34
self .protocol = protocol
35
35
36
+ @property
37
+ def is_valid (self ):
38
+ return self .generation_id != DEFAULT_GENERATION_ID
39
+
40
+ def __eq__ (self , other ):
41
+ return (self .generation_id == other .generation_id and
42
+ self .member_id == other .member_id and
43
+ self .protocol == other .protocol )
44
+
45
+
36
46
Generation .NO_GENERATION = Generation (DEFAULT_GENERATION_ID , UNKNOWN_MEMBER_ID , None )
37
47
38
48
@@ -461,7 +471,8 @@ def join_group(self, timeout_ms=None):
461
471
exception = future .exception
462
472
if isinstance (exception , (Errors .UnknownMemberIdError ,
463
473
Errors .RebalanceInProgressError ,
464
- Errors .IllegalGenerationError )):
474
+ Errors .IllegalGenerationError ,
475
+ Errors .MemberIdRequiredError )):
465
476
continue
466
477
elif not future .retriable ():
467
478
raise exception # pylint: disable-msg=raising-bad-type
@@ -491,7 +502,7 @@ def _send_join_group_request(self):
491
502
(protocol , metadata if isinstance (metadata , bytes ) else metadata .encode ())
492
503
for protocol , metadata in self .group_protocols ()
493
504
]
494
- version = self ._client .api_version (JoinGroupRequest , max_version = 3 )
505
+ version = self ._client .api_version (JoinGroupRequest , max_version = 4 )
495
506
if version == 0 :
496
507
request = JoinGroupRequest [version ](
497
508
self .group_id ,
@@ -585,6 +596,11 @@ def _handle_join_group_response(self, future, send_time, response):
585
596
future .failure (error )
586
597
elif error_type is Errors .GroupAuthorizationFailedError :
587
598
future .failure (error_type (self .group_id ))
599
+ elif error_type is Errors .MemberIdRequiredError :
600
+ # Broker requires a concrete member id to be allowed to join the group. Update member id
601
+ # and send another join group request in next cycle.
602
+ self .reset_generation (response .member_id )
603
+ future .failure (error_type ())
588
604
else :
589
605
# unexpected error, throw the exception
590
606
error = error_type ()
@@ -762,10 +778,10 @@ def generation(self):
762
778
return None
763
779
return self ._generation
764
780
765
- def reset_generation (self ):
766
- """Reset the generation and memberId because we have fallen out of the group."""
781
+ def reset_generation (self , member_id = UNKNOWN_MEMBER_ID ):
782
+ """Reset the generation and member_id because we have fallen out of the group."""
767
783
with self ._lock :
768
- self ._generation = Generation . NO_GENERATION
784
+ self ._generation = Generation ( DEFAULT_GENERATION_ID , member_id , None )
769
785
self .rejoin_needed = True
770
786
self .state = MemberState .UNJOINED
771
787
@@ -799,8 +815,10 @@ def _close_heartbeat_thread(self, timeout_ms=None):
799
815
self ._heartbeat_thread = None
800
816
801
817
def __del__ (self ):
802
- if hasattr ( self , '_heartbeat_thread' ) :
818
+ try :
803
819
self ._close_heartbeat_thread ()
820
+ except (TypeError , AttributeError ):
821
+ pass
804
822
805
823
def close (self , timeout_ms = None ):
806
824
"""Close the coordinator, leave the current group,
@@ -816,7 +834,7 @@ def maybe_leave_group(self, timeout_ms=None):
816
834
with self ._client ._lock , self ._lock :
817
835
if (not self .coordinator_unknown ()
818
836
and self .state is not MemberState .UNJOINED
819
- and self ._generation is not Generation . NO_GENERATION ):
837
+ and self ._generation . is_valid ):
820
838
821
839
# this is a minimal effort attempt to leave the group. we do not
822
840
# attempt any resending if the request fails or times out.
0 commit comments