squah-confluent commented on code in PR #23322:
URL: https://github.com/apache/kafka/pull/23322#discussion_r3902880404


##########
group-coordinator/src/main/java/org/apache/kafka/coordinator/group/GroupCoordinatorConfig.java:
##########
@@ -535,7 +541,8 @@ public class GroupCoordinatorConfig {
         .define(STREAMS_GROUP_MAX_WARMUP_REPLICAS_CONFIG, INT, 
STREAMS_GROUP_MAX_WARMUP_REPLICAS_DEFAULT, atLeast(0), MEDIUM, 
STREAMS_GROUP_MAX_WARMUP_REPLICAS_DOC)
         .define(STREAMS_GROUP_RACK_AWARE_ASSIGNMENT_TAGS_CONFIG, LIST, 
STREAMS_GROUP_RACK_AWARE_ASSIGNMENT_TAGS_DEFAULT, 
ConfigDef.ValidList.anyNonDuplicateValues(true, false), LOW, 
STREAMS_GROUP_RACK_AWARE_ASSIGNMENT_TAGS_DOC)
         .define(STREAMS_GROUP_TOPOLOGY_DESCRIPTION_PLUGIN_CLASS_CONFIG, CLASS, 
STREAMS_GROUP_TOPOLOGY_DESCRIPTION_PLUGIN_CLASS_DEFAULT, MEDIUM, 
STREAMS_GROUP_TOPOLOGY_DESCRIPTION_PLUGIN_CLASS_DOC)
-        .define(STREAMS_GROUP_ACCEPTABLE_RECOVERY_LAG_CONFIG, LONG, 
STREAMS_GROUP_ACCEPTABLE_RECOVERY_LAG_DEFAULT, atLeast(0L), MEDIUM, 
STREAMS_GROUP_ACCEPTABLE_RECOVERY_LAG_DOC);
+        .define(STREAMS_GROUP_ACCEPTABLE_RECOVERY_LAG_CONFIG, LONG, 
STREAMS_GROUP_ACCEPTABLE_RECOVERY_LAG_DEFAULT, atLeast(0L), MEDIUM, 
STREAMS_GROUP_ACCEPTABLE_RECOVERY_LAG_DOC)
+        .defineInternal(STREAMS_GROUP_ASSIGNMENT_REFINER_CLASS_CONFIG, CLASS, 
STREAMS_GROUP_ASSIGNMENT_REFINER_CLASS_DEFAULT, null, LOW, 
STREAMS_GROUP_ASSIGNMENT_REFINER_CLASS_DOC);

Review Comment:
   Can we try to pick an ordering with respect to acceptable recovery lag?
   
   Above we define the constants before 
STREAMS_GROUP_ACCEPTABLE_RECOVERY_LAG_CONFIG. Here we define the config after 
acceptable recovery lag and the getter below is far away from the recovery lag 
getter.



##########
group-coordinator/src/main/java/org/apache/kafka/coordinator/group/GroupMetadataManager.java:
##########
@@ -370,6 +372,11 @@ Builder withStreamsGroupAssignors(List<TaskAssignor> 
streamsGroupAssignors) {
             return this;
         }
 
+        Builder withAssignmentRefiner(AssignmentRefiner assignmentRefiner) {

Review Comment:
   Can we rename this to `withStreamsGroupAssignmentRefiner`?
   
   Same for `GroupMetadataManagerTestContext`.



##########
group-coordinator/src/main/java/org/apache/kafka/coordinator/group/GroupMetadataManager.java:
##########
@@ -329,6 +330,7 @@ public static class Builder {
         private GroupCoordinatorMetricsShard metrics;
         private Optional<Plugin<Authorizer>> authorizerPlugin = null;
         private List<TaskAssignor> streamsGroupAssignors = null;
+        private AssignmentRefiner assignmentRefiner = null;

Review Comment:
   Can we rename this to `streamsGroupAssignmentRefiner`?
   
   Same for `GroupMetadataManagerTestContext`.



##########
group-coordinator/src/main/java/org/apache/kafka/coordinator/group/GroupCoordinatorConfig.java:
##########
@@ -1065,6 +1072,21 @@ public boolean 
isStreamsGroupTopologyDescriptionPluginConfigured() {
         return 
config.getClass(STREAMS_GROUP_TOPOLOGY_DESCRIPTION_PLUGIN_CLASS_CONFIG) != null;
     }
 
+    /**
+     * The assignment refiner to derive the intermediate assignment of a 
streams group with, or {@code null} if none is
+     * configured, in which case the caller falls back to {@link 
NoOpAssignmentRefiner}.
+     * <p>
+     * Instantiated on demand rather than held in a field, because a {@code 
GroupCoordinatorConfig} is constructed
+     * whenever any dynamic broker config changes ({@code 
DynamicBrokerConfig.processReconfiguration} builds a whole
+     * {@code KafkaConfig}), and we do not want to construct a refiner for 
each of those. A shard asks for one when it
+     * is loaded, so every shard gets its own instance.
+     */

Review Comment:
   Claude has a habit of oversharing in comments and I am not a fan of it. It's 
really challenging to trim down since everything it includes is _true_. For 
method javadocs we can try approaching it from the angle of "what does the 
caller need to know?" and these items fall out:
   
   * When `null`, it is up to the caller to choose a default. It doesn't make 
sense to tell the caller that they have chosen `NoOpAssignmentRefiner` as the 
default.
   * The caller is interested in knowing that each call constructs a fresh 
instance, since refiners are not thread safe. The part about shards is an 
implementation detail of the caller.
   * The reasoning about not instantiating in the constructor is an 
implementation detail and belongs in a comment (but we wouldn't do that anyway 
since each call wants to return a fresh instance).



##########
group-coordinator/src/main/java/org/apache/kafka/coordinator/group/streams/AssignmentRefiner.java:
##########
@@ -44,11 +45,20 @@
  *     the decisions of a step are taken once, when the epoch is minted, and 
do not change while the members reconcile
  *     towards it. See {@link StreamsGroup#refinedAssignment(int)}.</li>
  * </ul>
+ * <p>
+ * One instance is created per coordinator shard, and serves every streams 
group on that shard: the two configurations
+ * a refinement depends on are per-group overridable and are therefore passed 
in on every call rather than held as
+ * instance state. Since a shard is single-threaded, an implementation does 
not have to be thread-safe unless it shares
+ * state across shards.
+ * <p>
+ * The default is {@link NoOpAssignmentRefiner}. Which implementation is used 
is not a public extension point; it is
+ * selected by an internal broker configuration
+ * ({@code 
GroupCoordinatorConfig.STREAMS_GROUP_ASSIGNMENT_REFINER_CLASS_CONFIG}) that 
exists so that tests can put a

Review Comment:
   writing style nit: No dramatic reveals please! Let's lead with what is 
(config decides the refiner) rather than what is not ("not a public extension 
point").



##########
group-coordinator/src/main/java/org/apache/kafka/coordinator/group/GroupCoordinatorConfig.java:
##########
@@ -433,6 +435,10 @@ public class GroupCoordinatorConfig {
     public static final Class<?> 
STREAMS_GROUP_TOPOLOGY_DESCRIPTION_PLUGIN_CLASS_DEFAULT = null;
     public static final String 
STREAMS_GROUP_TOPOLOGY_DESCRIPTION_PLUGIN_CLASS_DOC = "The fully qualified 
class name of a StreamsGroupTopologyDescriptionPlugin implementation. When not 
set, the feature is disabled.";
 
+    public static final String STREAMS_GROUP_ASSIGNMENT_REFINER_CLASS_CONFIG = 
"group.streams.assignment.refiner.class";
+    public static final Class<?> 
STREAMS_GROUP_ASSIGNMENT_REFINER_CLASS_DEFAULT = null;

Review Comment:
   I wonder if we should point the config-level default to the real default 
class (not strongly for or against)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to