async def _really_create_topic(self, owner: Service, client: aiokafka.AIOKafkaClient, topic: str, partitions: int, replication: int, *, config: Mapping[str, Any] = None, timeout: int = 30000, retention: int = None, compacting: bool = None, deleting: bool = None, ensure_created: bool = False) -> None: owner.log.info(f'Creating topic {topic}') if topic in client.cluster.topics(): owner.log.debug(f'Topic {topic} exists, skipping creation.') return protocol_version = 1 extra_configs = config or {} config = self._topic_config(retention, compacting, deleting) config.update(extra_configs) controller_node = await self._get_controller_node(owner, client, timeout=timeout) owner.log.info(f'Found controller: {controller_node}') if controller_node is None: if owner.should_stop: owner.log.info(f'Shutting down hence controller not found') return else: raise Exception(f'Controller node is None') request = CreateTopicsRequest[protocol_version]( [(topic, partitions, replication, [], list(config.items()))], timeout, False, ) wait_result = await owner.wait( client.send(controller_node, request), timeout=timeout, ) if wait_result.stopped: owner.log.info(f'Shutting down - skipping creation.') return response = wait_result.result assert len(response.topic_error_codes), 'single topic' _, code, reason = response.topic_error_codes[0] if code != 0: if not ensure_created and code == TopicExistsError.errno: owner.log.debug(f'Topic {topic} exists, skipping creation.') return elif code == NotControllerError.errno: raise RuntimeError(f'Invalid controller: {controller_node}') else: raise for_code(code)( f'Cannot create topic: {topic} ({code}): {reason}') else: owner.log.info(f'Topic {topic} created.') return
async def _really_create_topic(self, owner: Service, client: aiokafka.AIOKafkaClient, topic: str, partitions: int, replication: int, *, config: Mapping[str, Any] = None, timeout: int = 30000, retention: int = None, compacting: bool = None, deleting: bool = None, ensure_created: bool = False) -> None: owner.log.info(f'Creating topic {topic}') protocol_version = 1 extra_configs = config or {} config = self._topic_config(retention, compacting, deleting) config.update(extra_configs) # Create topic request needs to be sent to the kafka cluster controller # Since aiokafka client doesn't currently support MetadataRequest # version 1, client.controller will always be None. Hence we cycle # through all brokers if we get Error 41 (not controller) until we # hit the controller nodes = [broker.nodeId for broker in client.cluster.brokers()] owner.log.info(f'Nodes: {nodes}') for node_id in nodes: if node_id is None: raise RuntimeError('Not connected to Kafka broker') request = CreateTopicsRequest[protocol_version]( [(topic, partitions, replication, [], list(config.items()))], timeout, False, ) wait_result = await owner.wait( client.send(node_id, request), timeout=timeout, ) if wait_result.stopped: owner.log.info(f'Shutting down - skipping creation.') return response = wait_result.result assert len(response.topic_error_codes), 'single topic' _, code, reason = response.topic_error_codes[0] if code != 0: if not ensure_created and code == TopicExistsError.errno: owner.log.debug( f'Topic {topic} exists, skipping creation.') return elif code == NotControllerError.errno: owner.log.debug(f'Broker: {node_id} is not controller.') continue else: raise for_code(code)( f'Cannot create topic: {topic} ({code}): {reason}') else: owner.log.info(f'Topic {topic} created.') return raise Exception(f'No controller found among brokers: {nodes}')