Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Discussion thread: here

JIRA: here 

Vote thread: here

Please keep the discussion on the mailing list rather than commenting on the wiki (wiki discussions get unwieldy fast).

...

We have attempted error handing in accepted KIP: KIP-691: Enhance Transactional Producer Exception Handling - Apache Kafka - Apache Software Foundation which we can perhaps leverage some of the work here.

...

Proposed Changes

We would new error types which will be extended by existing exceptions mentioned in below table.

Code Block
// Producer Abortable Transaction
public class AbortableTransactionException extends ApiException {
    ...
}

//Producer Retriable 
public class ProducerRetriableTransactionException extends ApiException {
 	...
}

//Producer Refresh and Retriable
public class ProducerRefreshRetriableTransactionException extends ApiException {
	...
}

//Application-Recoverable
public class ApplicationRecoverableTransactionException extends ApiException {
    ...
}

// Invalid-Configuration
public class InvalidConfiguationTransactionException extends ApiException {
 	...
}

Client side code example

are proposing to group exceptions into four types:

  1. Producer-Retriable: mostly maps onto current retriable errors. Some of these errors may indicate that a metadata update at the producer level is required. Because of that we introduce a few subclasses to the retriable error

    1. retry only (just send the request again – after some period of backoff)

    2. refresh metadata and retry (request metadata and maybe modify the request before resending)NOTE: The producer can handle the retry on its own and the failure is invisible to the application layer.

  2. Producer-Abortable: mostly maps onto abortable errors. The error is bubbled to the application layer, and it can choose to roll back any state from the ongoing transaction and abort the transaction. The producer does not need to restart, as after aborting, it can be confident that the state was as it was before the transaction started. The application can also close the producer and react as it does for application-recoverable cases, but it doesn’t need to.
  3. Application-Recoverable: maps on to some fatal errors. The error is bubbled to the application layer, and it may need to do a bit more to roll back and clean up state. The producer can not simply abort and know the current state of the partitions. Applications can handle this in different ways – streams may rebalance a task and/or close the task and restart it. Another application may read from their own checkpoint to continue. In any case, the producer must restart and will be unusable after encountering this error.

  4. Invalid-Configuration: maps to some fatal errors. The error is bubbled up to the application layer. The application can decide what to do. The producer doesn’t need to restart, but the application may chose to close it.

Each error code always represent the same class and rarely rely on client state to determine how to handle.

While it is good to have a mapping, I think it is also useful to have a general strategy – ie a typical unknown error (not specified by the client to have a type) should probably be application recoverable.

Exception Table 

Below table contains list of exceptions with current and New handing. All exceptions are grouped under a header which represent Exception Name:

Yellow Image Added → Needs modification

Green Image Added → New exceptions added as part of this KIP

Check Image AddedException handling match as mentioned in KIP-691

Cross Image AddedException handling doesn't match as mentioned in KIP-691

AbortableTransactionException

Exception/Error Names

Current handling

New Handling


Producer API

Transaction API

Producer API

Transaction API

TransactionAbortableException
** note – Added via KIP-890

Producer Abortable

Producer Abortable

Producer Abortable

Producer Abortable

ProducerRetriableTransactionException

Exception/Error Names

Current handling

New Handling


Producer API

Transaction API

Producer API

Transaction API

CorruptRecordException

NotEnoughReplicasAfterAppendException

NotEnoughReplicasException

TimeoutException

Retriable if the error is retriable. Otherwise abortable

Retriable if the error is retriable otherwise abortable

Producer Retriable Image Added

Producer Retriable Image Added

ConcurrentTransactionsException

Retriable

Retriable

Producer Retriable (KIP-890 may see this)

Producer Retriable

CoordinatorLoadInProgressException

Retriable

Retriable

Producer Retriable

Producer Retriable

OutOfOrderSequenceException

Sometimes retriable or abortable

N/A

Producer Retriable Image Added

N/A

ProducerRefreshRetriableTransactionException

Exception/Error Names

Current handling

New Handling


Producer API

Transaction API

Producer API

Transaction API

UnknownTopicOrPartitionException

NotLeaderOrFollowerException

Retriable if the error is retriable. Otherwise abortable

Retriable if the error is retriable otherwise abortable

Refresh + Retriable Image Added

Refresh + Retriable Image Added

NotCoordinatorException

CoordinatorNotAvailableException

Retriable

Retriable

Refresh + Retriable

Refresh + Retriable

ApplicationRecoverableTransactionException

Exception/Error Names

Current handling

New Handling


Producer API

Transaction API

Producer API

Transaction API

IllegalStateException

Abortable

Sometimes Fatal depending on whether application or Sender caused issue. See: kafka: KAFKA-14831: Illegal state errors should be fatal in transactional producerCLOSED

Application Recoverable (probably not expected) Image Added

Application RecoverableImage Added

InvalidProducerEpochException

Abortable

Fatal

Application Recoverable Image Added

Application Recoverable Image Added

ProducerFencedException

Fatal

Fatal

Application Recoverable Image Added

Application Recoverable Image Added

InvalidPidMappingException

Sometimes retriable (no longer returned) or abortable

Abortable

Application Recoverable Image Added

Application Recoverable Image Added

UnknownProducerIdException

Sometimes retriable (no longer returned) or abortable

Abortable

Application Recoverable Image Added

Application Recoverable Image Added

FencedInstanceIdException

CommitFailedException

UnknownMemberIdException

IllegalGenerationExceiption

N/A

Abortable (TxnOffsetCommit Only)

N/A

Application Recoverable Image Added

KafkaException

Abortable (default seems to be abortable)

Fatal in most cases, but abortable when there are partition errors

Application Recoverable (not expected) Image Added

Application Recoverable (not expected) Image Added

RuntimeException

Abortable (default seems to be abortable)

Fatal – only thrown as this generic type when correlation ID is wrong. This should be updated as KIP-691 suggests

Application Recoverable (not expected) Image Added

Application Recoverable (not expected) Image Added

CorrelationIdMismatchException



Application Recoverable

Application Recoverable

InvalidConfiguationTransactionException

Exception/Error Names

Current handling

Expected Handling


Producer API

Transaction API

Producer API

Transaction API

AuthenticationException

Abortable

Fatal

Invalid Configuration Image Added

Invalid Configuration (not expected) Image Added

ClusterAuthorizationException

TransactionalIdAuthorizationException

UnsupportedVersionException

UnsupportedForMessageFormatException

Fatal, except UnsupportedForMessageFormatException which is Abortable

Cluster/Transaction Auth → abortable on InitProducerId, other errors abortable

TransactionAuth → fatal, others abortable for AddPartitions, Find Coordinator, EndTxn, AddOffsets

Transaction Auth, UnssupportedForMessageFormat → fatal for OffsetCommit

Invalid Configuration Image Added

Invalid Configuration Image Added

InvalidRecordException

InvalidRequiredAcksException

RecordBatchTooLargeException

InvalidTopicException

Retriable if the error is retriable. Otherwise abortable

Retriable if the error is retriable otherwise abortable

Invalid Configuration Image Added

Invalid Configuration Image Added

TopicAuthorizationException

GroupAuthorizationException

Abortable

Abortable

Invalid Configuration Image Added

Invalid Configuration Image Added


InvalidTxnStateException requires special handling where producer API and Transactional API has different handling:

Exception/Error Names

Current handling

Expected Handling


Producer API

Transaction API

Producer API

Transaction API

InvalidTxnStateException

Abortable

Fatal

Producer Abortable (KIP-890 relies on this – note this is the only one that differs with Produce API) Image Added

Application Recoverable Image Added

Public Interfaces

We will add new exception types, as listed in the table below, that extend the existing exceptions.

Code Block
// Producer Abortable Transaction
public class AbortableTransactionException extends ApiException {
    ...
}

//Producer Retriable 
public class ProducerRetriableTransactionException extends ApiException {
 	...
}

//Producer Refresh and Retriable
public class ProducerRefreshRetriableTransactionException extends ApiException {
	...
}

//Application-Recoverable
public class ApplicationRecoverableTransactionException extends ApiException {
    ...
}

// Invalid-Configuration
public class InvalidConfiguationTransactionException extends ApiException {
 	...
}

Client side code example

Code Block
public class TransactionalClientDemo {

    private static final String CONSUMER_GROUP_ID = "my-group-id";
    private static final String OUTPUT_TOPIC = "output";
    private static final String INPUT_TOPIC = "input";
    private static KafkaConsumer<String, String> consumer;
    private static KafkaProducer<String, String> producer;

    public static void main(String[] args) {
        initializeApplication();
Code Block
public class TransactionalClientDemo {

    private static final String CONSUMER_GROUP_ID = "my-group-id";
    private static final String OUTPUT_TOPIC = "output";
    private static final String INPUT_TOPIC = "input";
    private static KafkaConsumer<String, String> consumer;
    private static KafkaProducer<String, String> producer;

    public static void main(String[] args) {
        initializeApplication();

        boolean isRunning = true;
        // Continuously poll for records
        while (isRunning) {
            try {
                try {
                    // Poll records from Kafka for a timeout of 60 seconds
                    ConsumerRecords<String, String> records = consumer.poll(ofSeconds(60));

                    // Process records to generate word count map
                    Map<String, Integer> wordCountMap = new HashMap<>();

                    for (ConsumerRecord<String, String> record : records) {
                        String[] words = record.value().split(" ");
                        for (String word : words) {
                            wordCountMap.merge(word, 1, Integer::sum);
                        }
                    }

                    // Begin transaction
                    producer.beginTransaction();

                    // Produce word count results to output topic
                    wordCountMap.forEach((key, value) ->
                            producer.send(new ProducerRecord<>(OUTPUT_TOPIC, key, value.toString())));

                    // Determine offsets to commit
                    Map<TopicPartition, OffsetAndMetadata> offsetsToCommit = new HashMap<>();
                    for (TopicPartition partition : records.partitions()) {
                        List<ConsumerRecord<String, String>> partitionedRecords = records.records(partition);
                        long offset = partitionedRecords.get(partitionedRecords.size() - 1).offset();
                        offsetsToCommit.put(partition, new OffsetAndMetadata(offset + 1));
                    }

        boolean isRunning =  true;
        // SendContinuously offsets topoll transaction for atomic commitrecords
        while (isRunning) {
            producer.sendOffsetsToTransaction(offsetsToCommit, CONSUMER_GROUP_ID);

try {
                try {
    // Commit transaction
              // Poll records from Kafka  producer.commitTransaction();
    for a timeout of 60 seconds
            } catch (AbortableTransactionException e) {
    ConsumerRecords<String, String> records = consumer.poll(ofSeconds(60));

             // Abortable Exception: Handle Kafka exception by aborting// transaction. producer.abortTransaction() should not throw abortable exception.
Process records to generate word count map
                     producer.abortTransactionMap<String, Integer> wordCountMap = new HashMap<>();

                    for resetToLastCommittedPositions(consumer);
    (ConsumerRecord<String, String> record : records) {
            }
            String[] }words catch= (InvalidConfiguationTransactionException e) {record.value().split(" ");
                //  Fatal Error: The error is bubbled up to the application layer. The application can decide what to do
for (String word : words) {
                       closeAll();
     wordCountMap.merge(word, 1, Integer::sum);
         throw e;
            } catch (KafkaException}
 | ApplicationRecoverableTransactionException e) {
                //}

 Application Recoverable: The application must restart
              // Begin closeAll();transaction
                 initializeApplication   producer.beginTransaction();

                   }
 // Produce word count results to output }

topic
         }

Full example can be accessed at: https://github.com/apache/kafka/pull/15913/files 

Proposed Changes

We are proposing to group exceptions into four types:

  1. Producer-Retriable: mostly maps onto current retriable errors. The producer can handle the retry on its own and the failure is invisible to the application. Some of these errors may indicate that a metadata update at the producer level is required. Because of that we introduce a few subclasses to the retriable error

    1. retry only (just send the request again – after some period of backoff)

    2. refresh metadata and retry (request metadata and maybe modify the request before resending)

  2. Producer-Abortable: mostly maps onto abortable errors. The error is bubbled to the application layer, and it can choose to roll back any state from the ongoing transaction and abort the transaction. The producer does not need to restart, as after aborting, it can be confident that the state was as it was before the transaction started. The application can also close the producer and react as it does for application-recoverable cases, but it doesn’t need to.

  3. Application-Recoverable: maps on to some fatal errors. The error is bubbled to the application layer, and it may need to do a bit more to roll back and clean up state. The producer can not simply abort and know the current state of the partitions. Applications can handle this in different ways – streams may rebalance a task and/or close the task and restart it. Another application may read from their own checkpoint to continue. In any case, the producer must restart and will be unusable after encountering this error.

  4. Invalid-Configuration: maps to some fatal errors. The error is bubbled up to the application layer. The application can decide what to do. The producer doesn’t need to restart, but the application may chose to close it.

Each error code always represent the same class and rarely rely on client state to determine how to handle.

While it is good to have a mapping, I think it is also useful to have a general strategy – ie a typical unknown error (not specified by the client to have a type) should probably be application recoverable.

Exception Table 

Below table contains list of exceptions with current and New handing. All exceptions are grouped under a header which represent Exception Name:

Yellow Image Removed → Needs modification

Green Image Removed → New exceptions added as part of this KIP

Check Image RemovedException handling match as mentioned in KIP-691

Cross Image RemovedException handling doesn't match as mentioned in KIP-691

AbortableTransactionException

...

Exception/Error Names

...

Current handling

...

New Handling

...

Producer API

...

Transaction API

...

Producer API

...

Transaction API

...

TransactionAbortableException
** note – Added via KIP-890

...

Producer Abortable

...

Producer Abortable

...

Producer Abortable

...

Producer Abortable

...

TransactionAbortableException
** note – Added via KIP-890

...

Producer Abortable

...

Producer Abortable

...

Producer Abortable

...

Producer Abortable

ProducerRetriableTransactionException

...

Exception/Error Names

...

Current handling

...

New Handling

...

Producer API

...

Transaction API

...

Producer API

...

Transaction API

...

CorruptRecordException

NotEnoughReplicasAfterAppendException

NotEnoughReplicasException

TimeoutException

...

Retriable if the error is retriable. Otherwise abortable

...

Retriable if the error is retriable otherwise abortable

...

Producer Retriable Image Removed

...

Producer Retriable Image Removed

...

ConcurrentTransactionsException

...

Retriable

...

Retriable

...

Producer Retriable (KIP-890 may see this)

...

Producer Retriable

...

CoordinatorLoadInProgressException

...

Retriable

...

Retriable

...

Producer Retriable

...

Producer Retriable

...

OutOfOrderSequenceException

...

Sometimes retriable or abortable

...

N/A

...

Producer Retriable Image Removed

...

N/A

ProducerRefreshRetriableTransactionException

...

Exception/Error Names

...

Current handling

...

New Handling

...

Producer API

...

Transaction API

...

Producer API

...

Transaction API

...

UnknownTopicOrPartitionException

NotLeaderOrFollowerException

...

Retriable if the error is retriable. Otherwise abortable

...

Retriable if the error is retriable otherwise abortable

...

Refresh + Retriable Image Removed

...

Refresh + Retriable Image Removed

...

NotCoordinatorException

CoordinatorNotAvailableException

...

Retriable

...

Retriable

...

Refresh + Retriable

...

Refresh + Retriable

ApplicationRecoverableTransactionException

...

Exception/Error Names

...

Current handling

...

New Handling

...

Producer API

...

Transaction API

...

Producer API

...

Transaction API

...

IllegalStateException

...

Abortable

...

Sometimes Fatal depending on whether application or Sender caused issue. See: kafka: KAFKA-14831: Illegal state errors should be fatal in transactional producerCLOSED

...

Application Recoverable (probably not expected) Image Removed

...

Application RecoverableImage Removed

...

UnknownProducerIdException

...

Sometimes retriable (no longer returned) or abortable

...

Abortable

...

Application Recoverable Image Removed

...

Application Recoverable Image Removed

...

ProducerFencedException

...

Fatal

...

Fatal

...

Application Recoverable Image Removed

...

Application Recoverable Image Removed

...

InvalidProducerEpochException

...

Abortable

...

Fatal

...

Application Recoverable Image Removed

...

Application Recoverable Image Removed

...

ProducerFencedException

...

Fatal

...

Fatal

...

Application Recoverable Image Removed

...

Application Recoverable Image Removed

...

InvalidPidMappingException

...

Sometimes retriable (no longer returned) or abortable

...

Abortable

...

Application Recoverable Image Removed

...

Application Recoverable Image Removed

...

UnknownProducerIdException

...

Sometimes retriable (no longer returned) or abortable

...

Abortable

...

Application Recoverable Image Removed

...

Application Recoverable Image Removed

...

FencedInstanceIdException

CommitFailedException

UnknownMemberIdException

IllegalGenerationExceiption

...

N/A

...

Abortable (TxnOffsetCommit Only)

...

N/A

...

Application Recoverable Image Removed

...

KafkaException

...

Abortable (default seems to be abortable)

...

Fatal in most cases, but abortable when there are partition errors

...

Application Recoverable (not expected) Image Removed

...

Application Recoverable (not expected) Image Removed

...

RuntimeException

...

Abortable (default seems to be abortable)

...

Fatal – only thrown as this generic type when correlation ID is wrong. This should be updated as KIP-691 suggests

...

Application Recoverable (not expected) Image Removed

...

Application Recoverable (not expected) Image Removed

           wordCountMap.forEach((key, value) ->
                            producer.send(new ProducerRecord<>(OUTPUT_TOPIC, key, value.toString())));

                    // Determine offsets to commit
                    Map<TopicPartition, OffsetAndMetadata> offsetsToCommit = new HashMap<>();
                    for (TopicPartition partition : records.partitions()) {
                        List<ConsumerRecord<String, String>> partitionedRecords = records.records(partition);
                        long offset = partitionedRecords.get(partitionedRecords.size() - 1).offset();
                        offsetsToCommit.put(partition, new OffsetAndMetadata(offset + 1));
                    }

                    // Send offsets to transaction for atomic commit
                    producer.sendOffsetsToTransaction(offsetsToCommit, CONSUMER_GROUP_ID);

                    // Commit transaction
                    producer.commitTransaction();
                } catch (AbortableTransactionException e) {
                    // Abortable Exception: Handle Kafka exception by aborting transaction. producer.abortTransaction() should not throw abortable exception.
                    producer.abortTransaction();
                    resetToLastCommittedPositions(consumer);
                }
            } catch (InvalidConfiguationTransactionException e) {
                //  Fatal Error: The error is bubbled up to the application layer. The application can decide what to do
                closeAll();
                throw e;
            } catch (KafkaException | ApplicationRecoverableTransactionException e) {
                // Application Recoverable: The application must restart
                closeAll();
                initializeApplication();
            }
        }

    }

Full example can be accessed at: https://github.com/apache/kafka/pull/15913/files 

...

CorrelationIdMismatchException

...

Application Recoverable

...

Application Recoverable

InvalidConfiguationTransactionException

...

Exception/Error Names

...

Current handling

...

Expected Handling

...

Producer API

...

Transaction API

...

Producer API

...

Transaction API

...

AuthenticationException

...

Abortable

...

Fatal

...

Invalid Configuration Image Removed

...

Invalid Configuration (not expected) Image Removed

...

ClusterAuthorizationException

TransactionalIdAuthorizationException

UnsupportedVersionException

UnsupportedForMessageFormatException

...

Fatal, except UnsupportedForMessageFormatException which is Abortable

...

Cluster/Transaction Auth → abortable on InitProducerId, other errors abortable

TransactionAuth → fatal, others abortable for AddPartitions, Find Coordinator, EndTxn, AddOffsets

Transaction Auth, UnssupportedForMessageFormat → fatal for OffsetCommit

...

Invalid Configuration Image Removed

...

Invalid Configuration Image Removed

...

InvalidRecordException

InvalidRequiredAcksException

RecordBatchTooLargeException

InvalidTopicException

...

Retriable if the error is retriable. Otherwise abortable

...

Retriable if the error is retriable otherwise abortable

...

Invalid Configuration Image Removed

...

Invalid Configuration Image Removed

...

TopicAuthorizationException

GroupAuthorizationException

...

Abortable

...

Abortable

...

Invalid Configuration Image Removed

...

Invalid Configuration Image Removed

InvalidTxnStateException requires special handling where producer API and Transactional API has different handling:

...

Exception/Error Names

...

Current handling

...

Expected Handling

...

Producer API

...

Transaction API

...

Producer API

...

Transaction API

...

InvalidTxnStateException

...

Abortable

...

Fatal

...

Producer Abortable (KIP-890 relies on this – note this is the only one that differs with Produce API) Image Removed

...

Compatibility, Deprecation, and Migration Plan

...