Skip to content

KAFKA-20790: Promote streams assignor API to public module - #22788

Merged
mjsax merged 32 commits into
apache:trunkfrom
gabriellefu:kip1357
Jul 24, 2026
Merged

KAFKA-20790: Promote streams assignor API to public module#22788
mjsax merged 32 commits into
apache:trunkfrom
gabriellefu:kip1357

Conversation

@gabriellefu

@gabriellefu gabriellefu commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Part of KIP-1357.

This PR adds the newly defined public API as defined in KIP-1357 to
support customer broker side "streams" task assignors. It also
refactors the existing runtime code and StickyTaskAssignor to
use/implement the new public APIs.

org.apache.kafka.coordinator.group.api.assignor.streams (in
group-coordinator-api), all annotated with @InterfaceAudience.Public
and @InterfaceStability.Evolving.

Also fixes a latent bug: the old code incorrectly passed the old target
assignment into the assignor. This PR now ensures that we correctly pass
the current assignment instead.

Reviewers: Matthias J. Sax matthias@confluent.io, Sean Quah
squah@confluent.io

@gabriellefu gabriellefu changed the title KAFKA-20683: Add broker side custom assignors for "streams" groups KAFKA-20790: Add broker side custom assignors for "streams" groups Jul 8, 2026
@gabriellefu gabriellefu changed the title KAFKA-20790: Add broker side custom assignors for "streams" groups KAFKA-20790: Promote streams assignor API to public module Jul 9, 2026

@mjsax mjsax left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made a pass... Curious to hear from others.

@@ -24,6 +27,8 @@
*
* @param members The member assignments keyed by member ID.
*/
@InterfaceAudience.Public
@InterfaceStability.Evolving
public record GroupAssignment(Map<String, MemberAssignment> members) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The KIP defines this as a class, not a record. -- Given that this is an output/return type, not an input to the assignor, it might actually be ok to keep as record, and we could also update the KIP?

\cc @lianetm for input

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I will update my kip and make it into a record.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@squah-confluent squah-confluent Jul 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't follow the KIP too closely but I think the reason we went with a class is that it's easier to evolve in the future. When adding a new field, we can add a constructor overload and initialize it with a sensible default, whereas a record will require constructor changes and break any code that tries to use the old constructor signature.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so maybe it's easier to maintain for future evolving as a record? I can change it back and adding the corresponding code today

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When adding a new field, we can add a constructor overload and initialize it with a sensible default, whereas a record will require constructor changes and break any code that tries to use the old constructor signature.

record still allows to add an overloaded constructor... it's still true, that overall record is less flexible than class though, so I also don't have any objections to change all record types in public API to interface or class.

@github-actions github-actions Bot removed the triage PRs from the community label Jul 14, 2026
@gabriellefu
gabriellefu requested a review from mjsax July 20, 2026 16:41
@gabriellefu

Copy link
Copy Markdown
Contributor Author

Have updated base on your comment, plz take a look. thanks! @mjsax

@mjsax mjsax left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Gabby. Made a pass. 95% LGTM.

member.instanceId(),
member.rackId(),
targetAssignment.activeTasks(),
targetAssignment.standbyTasks(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems odd to me, that we are passing the targetAssignment data here... This sounds like a bug to me? I believe we should pass in "current assignment" instead.

\cc @squah-confluent -- looking into code for KIP-848, it seems we are also passing the target assignment. Wondering why?

        // Prepare the member spec for all members.
        members.forEach((memberId, member) ->
            memberSpecs.put(memberId, newMemberSubscriptionAndAssignment(
                member,
                targetAssignment.getOrDefault(memberId, Assignment.EMPTY),
                topicResolver
            ))
        );

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking into StickyTaskAssignor we use it in initialize() to compute "prev active tasks" and "prev standby tasks" but if we did not reconcile to the target assignment yet, we would be "sticky" for no reason...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's intentional and I don't recall the reasoning for it. It does lead to some weirdness, such as KAFKA-19405. I think we should discuss with @dajac.

gabriellefu and others added 3 commits July 22, 2026 00:03
…he/kafka/coordinator/group/api/streams/assignor/MemberAssignmentState.java

Co-authored-by: Matthias J. Sax <mjsax@apache.org>
# Conflicts:
#	group-coordinator/group-coordinator-api/src/main/java/org/apache/kafka/coordinator/group/api/streams/assignor/MemberAssignmentState.java
@gabriellefu
gabriellefu requested a review from mjsax July 23, 2026 02:33
);
}

private static List<StreamsGroupDescribeResponseData.TaskOffset> taskOffsetsFromMap(Map<TaskId, Long> offsets) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change here cause the taskoffset has been changed from Map<TaskId, Long> to Map<String, Map<Integer, Long>>

copyTasks(newMemberAssignment.activeTasks()),
copyTasks(newMemberAssignment.standbyTasks()),
// Warm-up tasks are not assigned by the assignor; they are decided during reconciliation.
Map.of()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Map.of()
new HashMap()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Map.of() return an unmodifiable map. If we make the extra effort to deep copy active and standby tasks to ensure it's modifiable, we should also ensure it for warmup tasks?

@mjsax mjsax added ci-approved streams kip Requires or implements a KIP KIP-1071 PRs related to KIP-1071 labels Jul 24, 2026

@mjsax mjsax left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left on minor comment, but we can also address in a follow up PR. Plan to merge after CI passed.

@mjsax
mjsax merged commit e51258d into apache:trunk Jul 24, 2026
52 of 55 checks passed
nileshkumar3 pushed a commit to nileshkumar3/kafka that referenced this pull request Jul 25, 2026
)

Part of KIP-1357.

This PR adds the newly defined public API as defined in KIP-1357 to
support  customer broker side "streams" task assignors. It also
refactors the existing  runtime code and StickyTaskAssignor to
use/implement the new public APIs.

`org.apache.kafka.coordinator.group.api.assignor.streams` (in
`group-coordinator-api`), all annotated with `@InterfaceAudience.Public`
and `@InterfaceStability.Evolving`.

Also fixes a latent bug: the old code incorrectly passed the old target
assignment into the assignor. This PR now ensures that we correctly pass
the current assignment instead.

Reviewers: Matthias J. Sax <matthias@confluent.io>, Sean Quah
 <squah@confluent.io>
public GroupAssignment(
Map<String, MemberAssignment> members
) {
this.members = Objects.requireNonNull(members);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excuse me, it seems most public interfaces introduced by KIP-1357 use immutable collections, but this one does not. Would you mind sharing the reasoning with me?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gabriellefu -- Seems we missed this one. GroupAssignment is a return type from the assignor to the broker, so making a defensive copy using Map.copyOf(...) seems to be the right thing to do.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The output side is currently guarded in TargetAssignmentBuilder, as TargetAssignmentBuilder#newMemberAssignment will deep copy the assignor's output using copyTasks(), so the server never holds a reference the assignor could mutate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do the change in a follow-up pr to make the api more aligned

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated in this pr, thanks #23165

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-approved group-coordinator kip Requires or implements a KIP KIP-1071 PRs related to KIP-1071 performance streams

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants