Search in sources :

Example 1 with ControlMessage

use of org.apache.hudi.connect.ControlMessage in project hudi by apache.

the class KafkaConnectControlAgent method start.

private void start() {
    Properties props = new Properties();
    props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
    // Todo fetch the worker id or name instead of a uuid.
    props.put(ConsumerConfig.GROUP_ID_CONFIG, "hudi-control-group" + UUID.randomUUID().toString());
    props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class);
    // Since we are using Kafka Control Topic as a RPC like interface,
    // we want consumers to only process messages that are sent after they come online
    props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");
    consumer = new KafkaConsumer<>(props, new StringDeserializer(), new ByteArrayDeserializer());
    consumer.subscribe(Collections.singletonList(controlTopicName));
    executorService.submit(() -> {
        while (true) {
            ConsumerRecords<String, byte[]> records;
            records = consumer.poll(Duration.ofMillis(KAFKA_POLL_TIMEOUT_MS));
            for (ConsumerRecord<String, byte[]> record : records) {
                try {
                    LOG.debug(String.format("Kafka consumerGroupId = %s topic = %s, partition = %s, offset = %s, customer = %s, country = %s", "", record.topic(), record.partition(), record.offset(), record.key(), record.value()));
                    ControlMessage message = ControlMessage.parseFrom(record.value());
                    String senderTopic = message.getTopicName();
                    if (message.getReceiverType().equals(ControlMessage.EntityType.PARTICIPANT)) {
                        if (partitionWorkers.containsKey(senderTopic)) {
                            for (TransactionParticipant partitionWorker : partitionWorkers.get(senderTopic)) {
                                partitionWorker.processControlEvent(message);
                            }
                        } else {
                            LOG.warn(String.format("Failed to send message for unregistered participants for topic %s", senderTopic));
                        }
                    } else if (message.getReceiverType().equals(ControlMessage.EntityType.COORDINATOR)) {
                        if (topicCoordinators.containsKey(senderTopic)) {
                            topicCoordinators.get(senderTopic).processControlEvent(message);
                        }
                    } else {
                        LOG.warn(String.format("Sender type of Control Message unknown %s", message.getSenderType().name()));
                    }
                } catch (Exception e) {
                    LOG.error(String.format("Fatal error while consuming a kafka record for topic = %s partition = %s", record.topic(), record.partition()), e);
                }
            }
            try {
                consumer.commitSync();
            } catch (CommitFailedException exception) {
                LOG.error("Fatal error while committing kafka control topic");
            }
        }
    });
}
Also used : TransactionParticipant(org.apache.hudi.connect.transaction.TransactionParticipant) StringDeserializer(org.apache.kafka.common.serialization.StringDeserializer) Properties(java.util.Properties) ByteArrayDeserializer(org.apache.kafka.common.serialization.ByteArrayDeserializer) CommitFailedException(org.apache.kafka.clients.consumer.CommitFailedException) ControlMessage(org.apache.hudi.connect.ControlMessage) CommitFailedException(org.apache.kafka.clients.consumer.CommitFailedException)

Example 2 with ControlMessage

use of org.apache.hudi.connect.ControlMessage in project hudi by apache.

the class ConnectTransactionParticipant method handleEndCommit.

private void handleEndCommit(ControlMessage message) {
    if (ongoingTransactionInfo == null) {
        LOG.warn(String.format("END_COMMIT %s is received while we were NOT in active transaction", message.getCommitTime()));
        return;
    } else if (!ongoingTransactionInfo.getCommitTime().equals(message.getCommitTime())) {
        LOG.error(String.format("Fatal error received END_COMMIT with commit time %s while local transaction commit time %s", message.getCommitTime(), ongoingTransactionInfo.getCommitTime()));
        // Recovery: A new END_COMMIT from leader caused interruption to an existing transaction,
        // explicitly reset Kafka commit offset to ensure no data loss
        cleanupOngoingTransaction();
        syncKafkaOffsetWithLeader(message);
        return;
    }
    context.pause(partition);
    ongoingTransactionInfo.commitInitiated();
    // send Writer Status Message and wait for ACK_COMMIT in async fashion
    try {
        // sendWriterStatus
        List<WriteStatus> writeStatuses = ongoingTransactionInfo.getWriter().close();
        ControlMessage writeStatusEvent = ControlMessage.newBuilder().setProtocolVersion(KafkaConnectConfigs.CURRENT_PROTOCOL_VERSION).setType(ControlMessage.EventType.WRITE_STATUS).setTopicName(partition.topic()).setSenderType(ControlMessage.EntityType.PARTICIPANT).setSenderPartition(partition.partition()).setReceiverType(ControlMessage.EntityType.COORDINATOR).setReceiverPartition(ConnectTransactionCoordinator.COORDINATOR_KAFKA_PARTITION).setCommitTime(ongoingTransactionInfo.getCommitTime()).setParticipantInfo(ControlMessage.ParticipantInfo.newBuilder().setWriteStatus(KafkaConnectUtils.buildWriteStatuses(writeStatuses)).setKafkaOffset(ongoingTransactionInfo.getExpectedKafkaOffset()).build()).build();
        kafkaControlAgent.publishMessage(writeStatusEvent);
    } catch (Exception exception) {
        LOG.error(String.format("Error writing records and ending commit %s for partition %s", message.getCommitTime(), partition.partition()), exception);
        throw new HoodieIOException(String.format("Error writing records and ending commit %s for partition %s", message.getCommitTime(), partition.partition()), new IOException(exception));
    }
}
Also used : HoodieIOException(org.apache.hudi.exception.HoodieIOException) IOException(java.io.IOException) HoodieIOException(org.apache.hudi.exception.HoodieIOException) WriteStatus(org.apache.hudi.client.WriteStatus) ControlMessage(org.apache.hudi.connect.ControlMessage) HoodieException(org.apache.hudi.exception.HoodieException) IOException(java.io.IOException) HoodieIOException(org.apache.hudi.exception.HoodieIOException)

Aggregations

ControlMessage (org.apache.hudi.connect.ControlMessage)2 IOException (java.io.IOException)1 Properties (java.util.Properties)1 WriteStatus (org.apache.hudi.client.WriteStatus)1 TransactionParticipant (org.apache.hudi.connect.transaction.TransactionParticipant)1 HoodieException (org.apache.hudi.exception.HoodieException)1 HoodieIOException (org.apache.hudi.exception.HoodieIOException)1 CommitFailedException (org.apache.kafka.clients.consumer.CommitFailedException)1 ByteArrayDeserializer (org.apache.kafka.common.serialization.ByteArrayDeserializer)1 StringDeserializer (org.apache.kafka.common.serialization.StringDeserializer)1