def _perform_group_join(self): """Join the group and return the assignment for the next generation. This function handles both JoinGroup and SyncGroup, delegating to _perform_assignment() if elected leader by the coordinator. Returns: Future: resolves to the encoded-bytes assignment returned from the group leader """ if self.coordinator_unknown(): e = Errors.GroupCoordinatorNotAvailableError(self.coordinator_id) return Future().failure(e) # send a join group request to the coordinator log.debug("(Re-)joining group %s", self.group_id) request = JoinGroupRequest( self.group_id, self.config['session_timeout_ms'], self.member_id, self.protocol_type(), [(protocol, metadata if isinstance(metadata, bytes) else metadata.encode()) for protocol, metadata in self.group_protocols()]) # create the request for the coordinator log.debug("Issuing request (%s) to coordinator %s", request, self.coordinator_id) future = Future() _f = self._client.send(self.coordinator_id, request) _f.add_callback(self._handle_join_group_response, future) _f.add_errback(self._failed_request, self.coordinator_id, request, future) return future
def perform_group_join(self): """Join the group and return the assignment for the next generation. This function handles both JoinGroup and SyncGroup, delegating to _perform_assignment() if elected as leader by the coordinator node. Returns encoded-bytes assignment returned from the group leader """ # send a join group request to the coordinator log.info("(Re-)joining group %s", self.group_id) topics = self._subscription assert topics is not None, 'Consumer has not subscribed to topics' metadata_list = [] for assignor in self._assignors: metadata = assignor.metadata(topics) if not isinstance(metadata, bytes): metadata = metadata.encode() group_protocol = (assignor.name, metadata) metadata_list.append(group_protocol) request = JoinGroupRequest(self.group_id, self._session_timeout_ms, self._coordinator.member_id, ConsumerProtocol.PROTOCOL_TYPE, metadata_list) # create the request for the coordinator log.debug("Sending JoinGroup (%s) to coordinator %s", request, self.coordinator_id) try: response = yield from self._coordinator._send_req( self.coordinator_id, request, group=ConnectionGroup.COORDINATION) except Errors.GroupLoadInProgressError: log.debug( "Attempt to join group %s rejected since coordinator %s" " is loading the group.", self.group_id, self.coordinator_id) except Errors.UnknownMemberIdError: # reset the member id and retry immediately self._coordinator.member_id = JoinGroupRequest.UNKNOWN_MEMBER_ID log.debug( "Attempt to join group %s failed due to unknown member id", self.group_id) return except (Errors.GroupCoordinatorNotAvailableError, Errors.NotCoordinatorForGroupError) as err: # re-discover the coordinator and retry with backoff self._coordinator.coordinator_dead() log.debug( "Attempt to join group %s failed due to obsolete " "coordinator information: %s", self.group_id, err) except Errors.KafkaError as err: log.error("Error in join group '%s' response: %s", self.group_id, err) if not err.retriable: raise else: log.debug("Join group response %s", response) self._coordinator.member_id = response.member_id self._coordinator.generation = response.generation_id self._coordinator.rejoin_needed = False protocol = response.group_protocol log.info("Joined group '%s' (generation %s) with member_id %s", self.group_id, response.generation_id, response.member_id) if response.leader_id == response.member_id: log.info( "Elected group leader -- performing partition" " assignments using %s", protocol) cor = self._on_join_leader(response) else: cor = self._on_join_follower() try: member_assignment_bytes = yield from cor except (Errors.UnknownMemberIdError, Errors.RebalanceInProgressError, Errors.IllegalGenerationError): # The current group is already not correct, maybe we were too # slow and timeouted or a new rebalance is required. pass except Errors.KafkaError as err: if not err.retriable: raise else: return (protocol, member_assignment_bytes) # backoff wait - failure case yield from asyncio.sleep(self._retry_backoff_ms / 1000, loop=self.loop)