Skip to content

KAFKA-20790: add AssignmentConfigs interface - #23092

Open
gabriellefu wants to merge 15 commits into
apache:trunkfrom
gabriellefu:assignmentconfig
Open

KAFKA-20790: add AssignmentConfigs interface#23092
gabriellefu wants to merge 15 commits into
apache:trunkfrom
gabriellefu:assignmentconfig

Conversation

@gabriellefu

@gabriellefu gabriellefu commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Adding AssignmentConfigs a public API for KIP-1357.

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

@github-actions github-actions Bot removed the triage PRs from the community label Aug 7, 2026

@squah-confluent squah-confluent left a comment

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.

Thanks for updating the PR!

/**
* The configs used for a group that has none of them set.
*/
public static final AssignmentConfigsImpl DEFAULT = new AssignmentConfigsImpl(0, List.of());

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.

Where do we plan to define the default num.standby.replicas and rack.aware.assignment.tags? Can we have a single source of truth for the defaults?

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 added AssignmentConfigsImpl.DEFAULT which is the default value of all the single config in the configs(), and also added some helper to construct AssignmentConfigsImpl with all default value except certain configs


GroupAssignment result = assignor.assign(
new GroupSpecImpl(members, mkMap(mkEntry(NUM_STANDBY_REPLICAS_CONFIG, String.valueOf(numStandbyReplicas)))),
new GroupSpecImpl(members, new AssignmentConfigsImpl(numStandbyReplicas, List.of())),

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.

These constructor calls are still going to be annoying to update when we add new configs.
We could leave them be or we could try to tidy things up some more, for example, by adding helper methods to construct an AssignmentConfigsImpl with default values but a specific num.standby.replicas or rack.aware.assignment.tags (eg. a withNumStandbyReplicas)

(Only applies to calls where we would want to take the defaults for future configs.)

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 have another pr is to avoid epoch bump when there's new config being introduced. So I was thinking about implement the default part maybe after this pr is merged? #23088

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 close the other pr and put the change in this pr too

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.

hm I think the not-bumping logic belongs in separate PR. Maybe we could bring the constant definition forward? But I don't really mind as long as the final state is clean.

How do you imagine these new AssignmentConfigsImpl calls to look at the end of it all?

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.

sounds good, i can do that. In the tests we can only pass the configs we actually care about , otherwise they will use there default value, for replicas is 0 and for tag is "".

public static final AssignmentConfigsImpl DEFAULT = new AssignmentConfigsImpl(
GroupCoordinatorConfig.STREAMS_GROUP_NUM_STANDBY_REPLICAS_DEFAULT,
// The parsed form of STREAMS_GROUP_RACK_AWARE_ASSIGNMENT_TAGS_DEFAULT, which ConfigDef spells as "".
List.of()

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 default of "rack.aware.assignment.tags" is "", and if we directly parse it into a List, it will give a [""] instead of a empty list [], so we still hardcode the default here

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.

Hmmm... This still seems to be error prone? In the end, we should have a single source of truth... Should we rather use STREAMS_GROUP_RACK_AWARE_ASSIGNMENT_TAGS_DEFAULT and parse it into empty List? If the default changes, this code would update immediatly?

But on the other hand, it seem we are using DEFAULT only in tests, what make it somewhat questionable, if it's the right place to add it here?

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.

we also use DEFAULT in fromMap(), if the config is a empty map, it returns DEFAULT otherwise it parse the config. But I agree with the STREAMS_GROUP_RACK_AWARE_ASSIGNMENT_TAGS_DEFAULT part I will update accordingly.

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 have added a helper here to parse STREAMS_GROUP_RACK_AWARE_ASSIGNMENT_TAGS_DEFAULT

// ConfigDef has already validated to be non-empty and free of surrounding whitespace.
String rackAwareAssignmentTags = configs.get(RACK_AWARE_ASSIGNMENT_TAGS_CONFIG);
return new AssignmentConfigsImpl(
Integer.parseInt(configs.get(NUM_STANDBY_REPLICAS_CONFIG)),

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.

Don't we need null check here and translate it to 0 ?

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.

In the original code, for replicas, there are two path, one is the whole map is empty, then it's ok to not having replicas set and here we return DEFAULT, other than that, the replicas should always be in the config

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.

Ok. Seems we are scattered logic, making it hard to reason about this... No critical for 4.4 release, but wondering if we could do a follow up cleanup PR, streamlining this a little bit better to make it easier as a (human 🤣) reviewer to follow...

Maybe we should "unify" the raw Map<String, String> and AssignmentConfigsImpl somehow, to have a single object we use and pass around, an avoid converting the one into the other multiple times along the way, at different places.

* parses a {@code LIST} configuration: an empty value is an empty list, not a list holding an empty string.
*/
private static List<String> parseRackAwareAssignmentTags(String rackAwareAssignmentTags) {
return rackAwareAssignmentTags.isEmpty() ? List.of() : List.of(rackAwareAssignmentTags.split(","));

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.

isEmpty() checks for length() == 0, right? What about " " (or similar). Do we need to to do rackAwareAssignmentTags.trim().isEmpty()` ?

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 input of this will be the output of String.join(",", tags), in this case, there won't be " ". But I do feel like here the type has been a bit confusing, I will submit a follow up pr to clean up those things

@mjsax mjsax added streams kip Requires or implements a KIP labels Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants