-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-9966: add internal assignment listener to stabilize eos-beta upgrade test #8648
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
mjsax
merged 5 commits into
apache:trunk
from
ableegoldman:MINOR-assignment-callback-for-integration-tests
May 13, 2020
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
37bf2a6
refactor AssignorConfiguration some, add listener for callback
ableegoldman 21e51d2
remove get prefix
ableegoldman 3654b47
keep Ignore for now
ableegoldman c4c3ed6
checkstyle
ableegoldman 959e221
github review changes
ableegoldman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,59 +47,21 @@ public final class AssignorConfiguration { | |
|
|
||
| private final String logPrefix; | ||
| private final Logger log; | ||
| private final AssignmentConfigs assignmentConfigs; | ||
| @SuppressWarnings("deprecation") | ||
| private final org.apache.kafka.streams.processor.PartitionGrouper partitionGrouper; | ||
| private final String userEndPoint; | ||
| private final TaskManager taskManager; | ||
| private final StreamsMetadataState streamsMetadataState; | ||
| private final Admin adminClient; | ||
| private final int adminClientTimeout; | ||
| private final InternalTopicManager internalTopicManager; | ||
| private final CopartitionedTopicsEnforcer copartitionedTopicsEnforcer; | ||
|
|
||
| private final StreamsConfig streamsConfig; | ||
| private final Map<String, ?> internalConfigs; | ||
|
|
||
| @SuppressWarnings("deprecation") | ||
| public AssignorConfiguration(final Map<String, ?> configs) { | ||
| streamsConfig = new QuietStreamsConfig(configs); | ||
| internalConfigs = configs; | ||
|
|
||
| // Setting the logger with the passed in client thread name | ||
| logPrefix = String.format("stream-thread [%s] ", streamsConfig.getString(CommonClientConfigs.CLIENT_ID_CONFIG)); | ||
| final LogContext logContext = new LogContext(logPrefix); | ||
| log = logContext.logger(getClass()); | ||
|
|
||
| assignmentConfigs = new AssignmentConfigs(streamsConfig); | ||
|
|
||
| partitionGrouper = streamsConfig.getConfiguredInstance( | ||
| StreamsConfig.PARTITION_GROUPER_CLASS_CONFIG, | ||
| org.apache.kafka.streams.processor.PartitionGrouper.class | ||
| ); | ||
|
|
||
| final String configuredUserEndpoint = streamsConfig.getString(StreamsConfig.APPLICATION_SERVER_CONFIG); | ||
| if (configuredUserEndpoint != null && !configuredUserEndpoint.isEmpty()) { | ||
| try { | ||
| final String host = getHost(configuredUserEndpoint); | ||
| final Integer port = getPort(configuredUserEndpoint); | ||
|
|
||
| if (host == null || port == null) { | ||
| throw new ConfigException( | ||
| String.format( | ||
| "%s Config %s isn't in the correct format. Expected a host:port pair but received %s", | ||
| logPrefix, StreamsConfig.APPLICATION_SERVER_CONFIG, configuredUserEndpoint | ||
| ) | ||
| ); | ||
| } | ||
| } catch (final NumberFormatException nfe) { | ||
| throw new ConfigException( | ||
| String.format("%s Invalid port supplied in %s for config %s: %s", | ||
| logPrefix, configuredUserEndpoint, StreamsConfig.APPLICATION_SERVER_CONFIG, nfe) | ||
| ); | ||
| } | ||
| userEndPoint = configuredUserEndpoint; | ||
| } else { | ||
| userEndPoint = null; | ||
| } | ||
|
|
||
| { | ||
| final Object o = configs.get(StreamsConfig.InternalConfig.TASK_MANAGER_FOR_PARTITION_ASSIGNOR); | ||
| if (o == null) { | ||
|
|
@@ -119,25 +81,6 @@ public AssignorConfiguration(final Map<String, ?> configs) { | |
| taskManager = (TaskManager) o; | ||
| } | ||
|
|
||
| { | ||
| final Object o = configs.get(StreamsConfig.InternalConfig.STREAMS_METADATA_STATE_FOR_PARTITION_ASSIGNOR); | ||
| if (o == null) { | ||
| final KafkaException fatalException = new KafkaException("StreamsMetadataState is not specified"); | ||
| log.error(fatalException.getMessage(), fatalException); | ||
| throw fatalException; | ||
| } | ||
|
|
||
| if (!(o instanceof StreamsMetadataState)) { | ||
| final KafkaException fatalException = new KafkaException( | ||
| String.format("%s is not an instance of %s", o.getClass().getName(), StreamsMetadataState.class.getName()) | ||
| ); | ||
| log.error(fatalException.getMessage(), fatalException); | ||
| throw fatalException; | ||
| } | ||
|
|
||
| streamsMetadataState = (StreamsMetadataState) o; | ||
| } | ||
|
|
||
| { | ||
| final Object o = configs.get(StreamsConfig.InternalConfig.STREAMS_ADMIN_CLIENT); | ||
| if (o == null) { | ||
|
|
@@ -155,13 +98,8 @@ public AssignorConfiguration(final Map<String, ?> configs) { | |
| } | ||
|
|
||
| adminClient = (Admin) o; | ||
| internalTopicManager = new InternalTopicManager(adminClient, streamsConfig); | ||
| } | ||
|
|
||
| adminClientTimeout = streamsConfig.getInt(AdminClientConfig.REQUEST_TIMEOUT_MS_CONFIG); | ||
|
|
||
| copartitionedTopicsEnforcer = new CopartitionedTopicsEnforcer(logPrefix); | ||
|
|
||
| { | ||
| final String o = (String) configs.get(INTERNAL_TASK_ASSIGNOR_CLASS); | ||
| if (o == null) { | ||
|
|
@@ -172,8 +110,8 @@ public AssignorConfiguration(final Map<String, ?> configs) { | |
| } | ||
| } | ||
|
|
||
| public AtomicInteger getAssignmentErrorCode(final Map<String, ?> configs) { | ||
| final Object ai = configs.get(StreamsConfig.InternalConfig.ASSIGNMENT_ERROR_CODE); | ||
| public AtomicInteger assignmentErrorCode() { | ||
| final Object ai = internalConfigs.get(StreamsConfig.InternalConfig.ASSIGNMENT_ERROR_CODE); | ||
| if (ai == null) { | ||
| final KafkaException fatalException = new KafkaException("assignmentErrorCode is not specified"); | ||
| log.error(fatalException.getMessage(), fatalException); | ||
|
|
@@ -190,8 +128,8 @@ public AtomicInteger getAssignmentErrorCode(final Map<String, ?> configs) { | |
| return (AtomicInteger) ai; | ||
| } | ||
|
|
||
| public AtomicLong getNextScheduledRebalanceMs(final Map<String, ?> configs) { | ||
| final Object al = configs.get(InternalConfig.NEXT_SCHEDULED_REBALANCE_MS); | ||
| public AtomicLong nextScheduledRebalanceMs() { | ||
| final Object al = internalConfigs.get(InternalConfig.NEXT_SCHEDULED_REBALANCE_MS); | ||
| if (al == null) { | ||
| final KafkaException fatalException = new KafkaException("nextProbingRebalanceMs is not specified"); | ||
| log.error(fatalException.getMessage(), fatalException); | ||
|
|
@@ -209,8 +147,8 @@ public AtomicLong getNextScheduledRebalanceMs(final Map<String, ?> configs) { | |
| return (AtomicLong) al; | ||
| } | ||
|
|
||
| public Time getTime(final Map<String, ?> configs) { | ||
| final Object t = configs.get(InternalConfig.TIME); | ||
| public Time time() { | ||
| final Object t = internalConfigs.get(InternalConfig.TIME); | ||
| if (t == null) { | ||
| final KafkaException fatalException = new KafkaException("time is not specified"); | ||
| log.error(fatalException.getMessage(), fatalException); | ||
|
|
@@ -228,12 +166,27 @@ public Time getTime(final Map<String, ?> configs) { | |
| return (Time) t; | ||
| } | ||
|
|
||
| public TaskManager getTaskManager() { | ||
| public TaskManager taskManager() { | ||
| return taskManager; | ||
| } | ||
|
|
||
| public StreamsMetadataState getStreamsMetadataState() { | ||
| return streamsMetadataState; | ||
| public StreamsMetadataState streamsMetadataState() { | ||
| final Object o = internalConfigs.get(StreamsConfig.InternalConfig.STREAMS_METADATA_STATE_FOR_PARTITION_ASSIGNOR); | ||
| if (o == null) { | ||
| final KafkaException fatalException = new KafkaException("StreamsMetadataState is not specified"); | ||
| log.error(fatalException.getMessage(), fatalException); | ||
| throw fatalException; | ||
| } | ||
|
|
||
| if (!(o instanceof StreamsMetadataState)) { | ||
| final KafkaException fatalException = new KafkaException( | ||
| String.format("%s is not an instance of %s", o.getClass().getName(), StreamsMetadataState.class.getName()) | ||
| ); | ||
| log.error(fatalException.getMessage(), fatalException); | ||
| throw fatalException; | ||
| } | ||
|
|
||
| return (StreamsMetadataState) o; | ||
| } | ||
|
|
||
| public RebalanceProtocol rebalanceProtocol() { | ||
|
|
@@ -301,35 +254,61 @@ public int configuredMetadataVersion(final int priorVersion) { | |
| } | ||
|
|
||
| @SuppressWarnings("deprecation") | ||
| public org.apache.kafka.streams.processor.PartitionGrouper getPartitionGrouper() { | ||
| return partitionGrouper; | ||
| public org.apache.kafka.streams.processor.PartitionGrouper partitionGrouper() { | ||
| return streamsConfig.getConfiguredInstance( | ||
| StreamsConfig.PARTITION_GROUPER_CLASS_CONFIG, | ||
| org.apache.kafka.streams.processor.PartitionGrouper.class | ||
| ); | ||
| } | ||
|
|
||
| public String getUserEndPoint() { | ||
| return userEndPoint; | ||
| public String userEndPoint() { | ||
| final String configuredUserEndpoint = streamsConfig.getString(StreamsConfig.APPLICATION_SERVER_CONFIG); | ||
| if (configuredUserEndpoint != null && !configuredUserEndpoint.isEmpty()) { | ||
| try { | ||
| final String host = getHost(configuredUserEndpoint); | ||
| final Integer port = getPort(configuredUserEndpoint); | ||
|
|
||
| if (host == null || port == null) { | ||
| throw new ConfigException( | ||
| String.format( | ||
| "%s Config %s isn't in the correct format. Expected a host:port pair but received %s", | ||
| logPrefix, StreamsConfig.APPLICATION_SERVER_CONFIG, configuredUserEndpoint | ||
| ) | ||
| ); | ||
| } | ||
| } catch (final NumberFormatException nfe) { | ||
| throw new ConfigException( | ||
| String.format("%s Invalid port supplied in %s for config %s: %s", | ||
| logPrefix, configuredUserEndpoint, StreamsConfig.APPLICATION_SERVER_CONFIG, nfe) | ||
| ); | ||
| } | ||
| return configuredUserEndpoint; | ||
| } else { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| public Admin getAdminClient() { | ||
| public Admin adminClient() { | ||
| return adminClient; | ||
| } | ||
|
|
||
| public int getAdminClientTimeout() { | ||
| return adminClientTimeout; | ||
| public int adminClientTimeout() { | ||
| return streamsConfig.getInt(AdminClientConfig.REQUEST_TIMEOUT_MS_CONFIG); | ||
| } | ||
|
|
||
| public InternalTopicManager getInternalTopicManager() { | ||
| return internalTopicManager; | ||
| public InternalTopicManager internalTopicManager() { | ||
| return new InternalTopicManager(adminClient, streamsConfig); | ||
| } | ||
|
|
||
| public CopartitionedTopicsEnforcer getCopartitionedTopicsEnforcer() { | ||
| return copartitionedTopicsEnforcer; | ||
| public CopartitionedTopicsEnforcer copartitionedTopicsEnforcer() { | ||
| return new CopartitionedTopicsEnforcer(logPrefix); | ||
| } | ||
|
|
||
| public AssignmentConfigs getAssignmentConfigs() { | ||
| return assignmentConfigs; | ||
| public AssignmentConfigs assignmentConfigs() { | ||
| return new AssignmentConfigs(streamsConfig); | ||
| } | ||
|
|
||
| public TaskAssignor getTaskAssignor() { | ||
| public TaskAssignor taskAssignor() { | ||
| try { | ||
| return Utils.newInstance(taskAssignorClass, TaskAssignor.class); | ||
| } catch (final ClassNotFoundException e) { | ||
|
|
@@ -340,6 +319,27 @@ public TaskAssignor getTaskAssignor() { | |
| } | ||
| } | ||
|
|
||
| public AssignmentListener assignmentListener() { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the only non-cosmetic change in this class, along with the interface added below |
||
| final Object o = internalConfigs.get(InternalConfig.ASSIGNMENT_LISTENER); | ||
| if (o == null) { | ||
| return stable -> { }; | ||
| } | ||
|
|
||
| if (!(o instanceof AssignmentListener)) { | ||
| final KafkaException fatalException = new KafkaException( | ||
| String.format("%s is not an instance of %s", o.getClass().getName(), AssignmentListener.class.getName()) | ||
| ); | ||
| log.error(fatalException.getMessage(), fatalException); | ||
| throw fatalException; | ||
| } | ||
|
|
||
| return (AssignmentListener) o; | ||
| } | ||
|
|
||
| public interface AssignmentListener { | ||
| void onAssignmentComplete(final boolean stable); | ||
| } | ||
|
|
||
| public static class AssignmentConfigs { | ||
| public final long acceptableRecoveryLag; | ||
| public final int maxWarmupReplicas; | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for all the lines of changes here, but the inconsistent method signatures and object construction was making this class hard to follow. All I'm doing here is making the methods conform to the same style, and moving the construction of any config that isn't needed elsewhere to its getter method. This allows us to remove a lot of these class variables
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we know if the corresponding "getters" are called often or not? I guess the main idea behind having those member variables was to "parse" the config once as it's immutable anyway instead of each time a getter is called?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are not. We construct the
AssignorConfigurationobject once inStreamsPartitionAssignor#configureand call the getters immediately afterwards, and only there