Versions Compared

Key

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

Table of Contents

Users should not create instances of `ConsumerGroupMetadata`, and this class should not have any public constructor.

Ideally, it would only be an interface. We should do a KIP an deprecate both constructors, and make it an interface in AK 5.0 release.

Status

Current state: Under Discussion

Discussion thread: here

JIRA: here

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

Motivation

Since Kafka transactions protocol is improved by KIP-447: Producer scalability for exactly once semantics and Kafka Streams has already onbarded eos-v2 by KIP-732: Deprecate eos-alpha and replace eos-beta with eos-v2 we should also drop support for legacy transactions protocol (without Consumer Group generation id and member id) in Kafka Producer.

Present API informs developers that they should avoid legacy protocol by marking void sendOffsetsToTransaction(Map<TopicPartition,OffsetAndMetadata> offsets, String consumerGroupId) depracated, but still developers can easily use a non depreacated method void sendOffsetsToTransaction(Map<TopicPartition,OffsetAndMetadata> offsets, ConsumerGroupMetadata groupMetadata) and pass there ConsumerGroupMetadata instance created by hand using non deprecated constructor.

This situation is also quite confusing for migrating the legacy applications since the easiest way to make a code not use any deprecated API is to just wrap a string consumer group id to ConsumerGroupMetadata and pass it to the void sendOffsetsToTransaction(Map<TopicPartition,OffsetAndMetadata> offsets, ConsumerGroupMetadata groupMetadata) method without generation id and member id.

Users should not create instances of `ConsumerGroupMetadata`, and this class should not have any public constructorDescribe the problems you are trying to solve.

Public Interfaces

  • org/apache/kafka/clients/consumer/ConsumerGroupMetadata

Proposed Changes

...

ConsumerGroupMetadata class should be an interface, we should provide a new internal class for interface implementation and use java default scope for class visibility.

Code Block
languagejava
titleConsumerGroupMetadata
public interface ConsumerGroupMetadata {

    String groupId();

    int generationId();

    String memberId();

    Optional<String> groupInstanceId();
}


Code Block
languagejava
titleDefaultConsumerGroupMetadata
class DefaultConsumerGroupMetadata implements ConsumerGroupMetadata {
    private final String groupId;
    private final int generationId;
    private final String memberId;
    private final Optional<String> groupInstanceId;

    DefaultConsumerGroupMetadata(String groupId,
                                        int generationId,
                                        String memberId,
                                        Optional<String> groupInstanceId) {
        this.groupId = Objects.requireNonNull(groupId, "group.id can't be null");
        this.generationId = generationId;
        this.memberId = Objects.requireNonNull(memberId, "member.id can't be null");
        this.groupInstanceId = Objects.requireNonNull(groupInstanceId, "group.instance.id can't be null");
    }

    public String groupId() {
        return groupId;
    }

    public int generationId() {
        return generationId;
    }

    public String memberId() {
        return memberId;
    }

    public Optional<String> groupInstanceId() {
        return groupInstanceId;
    }

    @Override
    public String toString() {
        return String.format("GroupMetadata(groupId = %s, generationId = %d, memberId = %s, groupInstanceId = %s)",
            groupId,
            generationId,
            memberId,
            groupInstanceId.orElse(""));
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        final DefaultConsumerGroupMetadata that = (DefaultConsumerGroupMetadata) o;
        return generationId == that.generationId &&
            Objects.equals(groupId, that.groupId) &&
            Objects.equals(memberId, that.memberId) &&
            Objects.equals(groupInstanceId, that.groupInstanceId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(groupId, generationId, memberId, groupInstanceId);
    }

}


Compatibility, Deprecation, and Migration Plan

...