Merge from multilang-kclv3 branch: Add multi-lang support for new configs, refactor enums, and update documentation
This is a squash of commits a144dfaac117415c400e8786b98060f5660d4276 through 4185f6e72520744e8a18cd04c550bc57a1bfd298.
This commit is contained in:
parent
2524ef83c3
commit
67d54045c1
31 changed files with 1503 additions and 169 deletions
|
|
@ -104,6 +104,12 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Test -->
|
<!-- Test -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<version>5.11.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
|
|
@ -122,6 +128,13 @@
|
||||||
<version>1.3</version>
|
<version>1.3</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Using older version to be compatible with Java 8 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-junit-jupiter</artifactId>
|
||||||
|
<version>3.12.4</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ public class MultiLangDaemon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String propertiesFile(final MultiLangDaemonArguments arguments) {
|
String validateAndGetPropertiesFileName(final MultiLangDaemonArguments arguments) {
|
||||||
String propertiesFile = "";
|
String propertiesFile = "";
|
||||||
|
|
||||||
if (CollectionUtils.isNotEmpty(arguments.parameters)) {
|
if (CollectionUtils.isNotEmpty(arguments.parameters)) {
|
||||||
|
|
@ -216,9 +216,9 @@ public class MultiLangDaemon {
|
||||||
MultiLangDaemonArguments arguments = new MultiLangDaemonArguments();
|
MultiLangDaemonArguments arguments = new MultiLangDaemonArguments();
|
||||||
JCommander jCommander = daemon.buildJCommanderAndParseArgs(arguments, args);
|
JCommander jCommander = daemon.buildJCommanderAndParseArgs(arguments, args);
|
||||||
try {
|
try {
|
||||||
String propertiesFile = daemon.propertiesFile(arguments);
|
String propertiesFileName = daemon.validateAndGetPropertiesFileName(arguments);
|
||||||
daemon.configureLogging(arguments.logConfiguration);
|
daemon.configureLogging(arguments.logConfiguration);
|
||||||
MultiLangDaemonConfig config = daemon.buildMultiLangDaemonConfig(propertiesFile);
|
MultiLangDaemonConfig config = daemon.buildMultiLangDaemonConfig(propertiesFileName);
|
||||||
|
|
||||||
Scheduler scheduler = daemon.buildScheduler(config);
|
Scheduler scheduler = daemon.buildScheduler(config);
|
||||||
MultiLangRunner runner = new MultiLangRunner(scheduler);
|
MultiLangRunner runner = new MultiLangRunner(scheduler);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Amazon.com, Inc. or its affiliates.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package software.amazon.kinesis.multilang.config;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import software.amazon.awssdk.services.dynamodb.model.BillingMode;
|
||||||
|
import software.amazon.kinesis.coordinator.CoordinatorConfig.CoordinatorStateTableConfig;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class CoordinatorStateConfigBean {
|
||||||
|
|
||||||
|
interface CoordinatorStateConfigBeanDelegate {
|
||||||
|
String getCoordinatorStateTableName();
|
||||||
|
|
||||||
|
void setCoordinatorStateTableName(String value);
|
||||||
|
|
||||||
|
BillingMode getCoordinatorStateBillingMode();
|
||||||
|
|
||||||
|
void setCoordinatorStateBillingMode(BillingMode value);
|
||||||
|
|
||||||
|
long getCoordinatorStateReadCapacity();
|
||||||
|
|
||||||
|
void setCoordinatorStateReadCapacity(long value);
|
||||||
|
|
||||||
|
long getCoordinatorStateWriteCapacity();
|
||||||
|
|
||||||
|
void setCoordinatorStateWriteCapacity(long value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = CoordinatorStateTableConfig.class, methodName = "tableName")
|
||||||
|
private String coordinatorStateTableName;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = CoordinatorStateTableConfig.class, methodName = "billingMode")
|
||||||
|
private BillingMode coordinatorStateBillingMode;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = CoordinatorStateTableConfig.class, methodName = "readCapacity")
|
||||||
|
private long coordinatorStateReadCapacity;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = CoordinatorStateTableConfig.class, methodName = "writeCapacity")
|
||||||
|
private long coordinatorStateWriteCapacity;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Amazon.com, Inc. or its affiliates.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package software.amazon.kinesis.multilang.config;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import software.amazon.kinesis.leases.LeaseManagementConfig;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class GracefulLeaseHandoffConfigBean {
|
||||||
|
|
||||||
|
interface GracefulLeaseHandoffConfigBeanDelegate {
|
||||||
|
Long getGracefulLeaseHandoffTimeoutMillis();
|
||||||
|
|
||||||
|
void setGracefulLeaseHandoffTimeoutMillis(Long value);
|
||||||
|
|
||||||
|
Boolean getIsGracefulLeaseHandoffEnabled();
|
||||||
|
|
||||||
|
void setIsGracefulLeaseHandoffEnabled(Boolean value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = LeaseManagementConfig.GracefulLeaseHandoffConfig.class)
|
||||||
|
private Long gracefulLeaseHandoffTimeoutMillis;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = LeaseManagementConfig.GracefulLeaseHandoffConfig.class)
|
||||||
|
private Boolean isGracefulLeaseHandoffEnabled;
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,7 @@ package software.amazon.kinesis.multilang.config;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
@ -41,6 +42,7 @@ import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
|
||||||
import software.amazon.awssdk.regions.Region;
|
import software.amazon.awssdk.regions.Region;
|
||||||
import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
|
import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
|
||||||
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
||||||
|
import software.amazon.awssdk.services.dynamodb.model.BillingMode;
|
||||||
import software.amazon.awssdk.services.kinesis.KinesisAsyncClient;
|
import software.amazon.awssdk.services.kinesis.KinesisAsyncClient;
|
||||||
import software.amazon.awssdk.services.kinesis.KinesisAsyncClientBuilder;
|
import software.amazon.awssdk.services.kinesis.KinesisAsyncClientBuilder;
|
||||||
import software.amazon.kinesis.checkpoint.CheckpointConfig;
|
import software.amazon.kinesis.checkpoint.CheckpointConfig;
|
||||||
|
|
@ -55,6 +57,7 @@ import software.amazon.kinesis.leases.ShardPrioritization;
|
||||||
import software.amazon.kinesis.lifecycle.LifecycleConfig;
|
import software.amazon.kinesis.lifecycle.LifecycleConfig;
|
||||||
import software.amazon.kinesis.metrics.MetricsConfig;
|
import software.amazon.kinesis.metrics.MetricsConfig;
|
||||||
import software.amazon.kinesis.metrics.MetricsLevel;
|
import software.amazon.kinesis.metrics.MetricsLevel;
|
||||||
|
import software.amazon.kinesis.multilang.config.converter.DurationConverter;
|
||||||
import software.amazon.kinesis.multilang.config.credentials.V2CredentialWrapper;
|
import software.amazon.kinesis.multilang.config.credentials.V2CredentialWrapper;
|
||||||
import software.amazon.kinesis.processor.ProcessorConfig;
|
import software.amazon.kinesis.processor.ProcessorConfig;
|
||||||
import software.amazon.kinesis.processor.ShardRecordProcessorFactory;
|
import software.amazon.kinesis.processor.ShardRecordProcessorFactory;
|
||||||
|
|
@ -156,6 +159,9 @@ public class MultiLangDaemonConfiguration {
|
||||||
@ConfigurationSettable(configurationClass = CoordinatorConfig.class)
|
@ConfigurationSettable(configurationClass = CoordinatorConfig.class)
|
||||||
private long schedulerInitializationBackoffTimeMillis;
|
private long schedulerInitializationBackoffTimeMillis;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = CoordinatorConfig.class)
|
||||||
|
private CoordinatorConfig.ClientVersionConfig clientVersionConfig;
|
||||||
|
|
||||||
@ConfigurationSettable(configurationClass = LifecycleConfig.class)
|
@ConfigurationSettable(configurationClass = LifecycleConfig.class)
|
||||||
private long taskBackoffTimeMillis;
|
private long taskBackoffTimeMillis;
|
||||||
|
|
||||||
|
|
@ -189,6 +195,20 @@ public class MultiLangDaemonConfiguration {
|
||||||
@Delegate(types = PollingConfigBean.PollingConfigBeanDelegate.class)
|
@Delegate(types = PollingConfigBean.PollingConfigBeanDelegate.class)
|
||||||
private final PollingConfigBean pollingConfig = new PollingConfigBean();
|
private final PollingConfigBean pollingConfig = new PollingConfigBean();
|
||||||
|
|
||||||
|
@Delegate(types = GracefulLeaseHandoffConfigBean.GracefulLeaseHandoffConfigBeanDelegate.class)
|
||||||
|
private final GracefulLeaseHandoffConfigBean gracefulLeaseHandoffConfigBean = new GracefulLeaseHandoffConfigBean();
|
||||||
|
|
||||||
|
@Delegate(
|
||||||
|
types = WorkerUtilizationAwareAssignmentConfigBean.WorkerUtilizationAwareAssignmentConfigBeanDelegate.class)
|
||||||
|
private final WorkerUtilizationAwareAssignmentConfigBean workerUtilizationAwareAssignmentConfigBean =
|
||||||
|
new WorkerUtilizationAwareAssignmentConfigBean();
|
||||||
|
|
||||||
|
@Delegate(types = WorkerMetricsTableConfigBean.WorkerMetricsTableConfigBeanDelegate.class)
|
||||||
|
private final WorkerMetricsTableConfigBean workerMetricsTableConfigBean = new WorkerMetricsTableConfigBean();
|
||||||
|
|
||||||
|
@Delegate(types = CoordinatorStateConfigBean.CoordinatorStateConfigBeanDelegate.class)
|
||||||
|
private final CoordinatorStateConfigBean coordinatorStateConfigBean = new CoordinatorStateConfigBean();
|
||||||
|
|
||||||
private boolean validateSequenceNumberBeforeCheckpointing;
|
private boolean validateSequenceNumberBeforeCheckpointing;
|
||||||
|
|
||||||
private long shutdownGraceMillis;
|
private long shutdownGraceMillis;
|
||||||
|
|
@ -252,6 +272,25 @@ public class MultiLangDaemonConfiguration {
|
||||||
},
|
},
|
||||||
InitialPositionInStream.class);
|
InitialPositionInStream.class);
|
||||||
|
|
||||||
|
convertUtilsBean.register(
|
||||||
|
new Converter() {
|
||||||
|
@Override
|
||||||
|
public <T> T convert(Class<T> type, Object value) {
|
||||||
|
return type.cast(CoordinatorConfig.ClientVersionConfig.valueOf(
|
||||||
|
value.toString().toUpperCase()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CoordinatorConfig.ClientVersionConfig.class);
|
||||||
|
|
||||||
|
convertUtilsBean.register(
|
||||||
|
new Converter() {
|
||||||
|
@Override
|
||||||
|
public <T> T convert(Class<T> type, Object value) {
|
||||||
|
return type.cast(BillingMode.valueOf(value.toString().toUpperCase()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BillingMode.class);
|
||||||
|
|
||||||
convertUtilsBean.register(
|
convertUtilsBean.register(
|
||||||
new Converter() {
|
new Converter() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -279,6 +318,8 @@ public class MultiLangDaemonConfiguration {
|
||||||
},
|
},
|
||||||
Region.class);
|
Region.class);
|
||||||
|
|
||||||
|
convertUtilsBean.register(new DurationConverter(), Duration.class);
|
||||||
|
|
||||||
ArrayConverter arrayConverter = new ArrayConverter(String[].class, new StringConverter());
|
ArrayConverter arrayConverter = new ArrayConverter(String[].class, new StringConverter());
|
||||||
arrayConverter.setDelimiter(',');
|
arrayConverter.setDelimiter(',');
|
||||||
convertUtilsBean.register(arrayConverter, String[].class);
|
convertUtilsBean.register(arrayConverter, String[].class);
|
||||||
|
|
@ -370,6 +411,22 @@ public class MultiLangDaemonConfiguration {
|
||||||
retrievalMode.builder(this).build(configsBuilder.kinesisClient(), this));
|
retrievalMode.builder(this).build(configsBuilder.kinesisClient(), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleCoordinatorConfig(CoordinatorConfig coordinatorConfig) {
|
||||||
|
ConfigurationSettableUtils.resolveFields(
|
||||||
|
this.coordinatorStateConfigBean, coordinatorConfig.coordinatorStateConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleLeaseManagementConfig(LeaseManagementConfig leaseManagementConfig) {
|
||||||
|
ConfigurationSettableUtils.resolveFields(
|
||||||
|
this.gracefulLeaseHandoffConfigBean, leaseManagementConfig.gracefulLeaseHandoffConfig());
|
||||||
|
ConfigurationSettableUtils.resolveFields(
|
||||||
|
this.workerUtilizationAwareAssignmentConfigBean,
|
||||||
|
leaseManagementConfig.workerUtilizationAwareAssignmentConfig());
|
||||||
|
ConfigurationSettableUtils.resolveFields(
|
||||||
|
this.workerMetricsTableConfigBean,
|
||||||
|
leaseManagementConfig.workerUtilizationAwareAssignmentConfig().workerMetricsTableConfig());
|
||||||
|
}
|
||||||
|
|
||||||
private Object adjustKinesisHttpConfiguration(Object builderObj) {
|
private Object adjustKinesisHttpConfiguration(Object builderObj) {
|
||||||
if (builderObj instanceof KinesisAsyncClientBuilder) {
|
if (builderObj instanceof KinesisAsyncClientBuilder) {
|
||||||
KinesisAsyncClientBuilder builder = (KinesisAsyncClientBuilder) builderObj;
|
KinesisAsyncClientBuilder builder = (KinesisAsyncClientBuilder) builderObj;
|
||||||
|
|
@ -448,6 +505,8 @@ public class MultiLangDaemonConfiguration {
|
||||||
processorConfig,
|
processorConfig,
|
||||||
retrievalConfig);
|
retrievalConfig);
|
||||||
|
|
||||||
|
handleCoordinatorConfig(coordinatorConfig);
|
||||||
|
handleLeaseManagementConfig(leaseManagementConfig);
|
||||||
handleRetrievalConfig(retrievalConfig, configsBuilder);
|
handleRetrievalConfig(retrievalConfig, configsBuilder);
|
||||||
|
|
||||||
resolveFields(configObjects, null, new HashSet<>(Arrays.asList(ConfigsBuilder.class, PollingConfig.class)));
|
resolveFields(configObjects, null, new HashSet<>(Arrays.asList(ConfigsBuilder.class, PollingConfig.class)));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Amazon.com, Inc. or its affiliates.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package software.amazon.kinesis.multilang.config;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import software.amazon.awssdk.services.dynamodb.model.BillingMode;
|
||||||
|
import software.amazon.kinesis.leases.LeaseManagementConfig.WorkerMetricsTableConfig;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class WorkerMetricsTableConfigBean {
|
||||||
|
|
||||||
|
interface WorkerMetricsTableConfigBeanDelegate {
|
||||||
|
String getWorkerMetricsTableName();
|
||||||
|
|
||||||
|
void setWorkerMetricsTableName(String value);
|
||||||
|
|
||||||
|
BillingMode getWorkerMetricsBillingMode();
|
||||||
|
|
||||||
|
void setWorkerMetricsBillingMode(BillingMode value);
|
||||||
|
|
||||||
|
long getWorkerMetricsReadCapacity();
|
||||||
|
|
||||||
|
void setWorkerMetricsReadCapacity(long value);
|
||||||
|
|
||||||
|
long getWorkerMetricsWriteCapacity();
|
||||||
|
|
||||||
|
void setWorkerMetricsWriteCapacity(long value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerMetricsTableConfig.class, methodName = "tableName")
|
||||||
|
private String workerMetricsTableName;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerMetricsTableConfig.class, methodName = "billingMode")
|
||||||
|
private BillingMode workerMetricsBillingMode;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerMetricsTableConfig.class, methodName = "readCapacity")
|
||||||
|
private long workerMetricsReadCapacity;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerMetricsTableConfig.class, methodName = "writeCapacity")
|
||||||
|
private long workerMetricsWriteCapacity;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Amazon.com, Inc. or its affiliates.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package software.amazon.kinesis.multilang.config;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import software.amazon.kinesis.leases.LeaseManagementConfig.WorkerUtilizationAwareAssignmentConfig;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class WorkerUtilizationAwareAssignmentConfigBean {
|
||||||
|
|
||||||
|
interface WorkerUtilizationAwareAssignmentConfigBeanDelegate {
|
||||||
|
long getInMemoryWorkerMetricsCaptureFrequencyMillis();
|
||||||
|
|
||||||
|
void setInMemoryWorkerMetricsCaptureFrequencyMillis(long value);
|
||||||
|
|
||||||
|
long getWorkerMetricsReporterFreqInMillis();
|
||||||
|
|
||||||
|
void setWorkerMetricsReporterFreqInMillis(long value);
|
||||||
|
|
||||||
|
int getNoOfPersistedMetricsPerWorkerMetrics();
|
||||||
|
|
||||||
|
void setNoOfPersistedMetricsPerWorkerMetrics(int value);
|
||||||
|
|
||||||
|
Boolean getDisableWorkerMetrics();
|
||||||
|
|
||||||
|
void setDisableWorkerMetrics(Boolean value);
|
||||||
|
|
||||||
|
double getMaxThroughputPerHostKBps();
|
||||||
|
|
||||||
|
void setMaxThroughputPerHostKBps(double value);
|
||||||
|
|
||||||
|
int getDampeningPercentage();
|
||||||
|
|
||||||
|
void setDampeningPercentage(int value);
|
||||||
|
|
||||||
|
int getReBalanceThresholdPercentage();
|
||||||
|
|
||||||
|
void setReBalanceThresholdPercentage(int value);
|
||||||
|
|
||||||
|
Boolean getAllowThroughputOvershoot();
|
||||||
|
|
||||||
|
void setAllowThroughputOvershoot(Boolean value);
|
||||||
|
|
||||||
|
int getVarianceBalancingFrequency();
|
||||||
|
|
||||||
|
void setVarianceBalancingFrequency(int value);
|
||||||
|
|
||||||
|
double getWorkerMetricsEMAAlpha();
|
||||||
|
|
||||||
|
void setWorkerMetricsEMAAlpha(double value);
|
||||||
|
|
||||||
|
void setStaleWorkerMetricsEntryCleanupDuration(Duration value);
|
||||||
|
|
||||||
|
Duration getStaleWorkerMetricsEntryCleanupDuration();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerUtilizationAwareAssignmentConfig.class)
|
||||||
|
private long inMemoryWorkerMetricsCaptureFrequencyMillis;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerUtilizationAwareAssignmentConfig.class)
|
||||||
|
private long workerMetricsReporterFreqInMillis;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerUtilizationAwareAssignmentConfig.class)
|
||||||
|
private int noOfPersistedMetricsPerWorkerMetrics;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerUtilizationAwareAssignmentConfig.class)
|
||||||
|
private Boolean disableWorkerMetrics;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerUtilizationAwareAssignmentConfig.class)
|
||||||
|
private double maxThroughputPerHostKBps;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerUtilizationAwareAssignmentConfig.class)
|
||||||
|
private int dampeningPercentage;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerUtilizationAwareAssignmentConfig.class)
|
||||||
|
private int reBalanceThresholdPercentage;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerUtilizationAwareAssignmentConfig.class)
|
||||||
|
private Boolean allowThroughputOvershoot;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerUtilizationAwareAssignmentConfig.class)
|
||||||
|
private int varianceBalancingFrequency;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerUtilizationAwareAssignmentConfig.class)
|
||||||
|
private double workerMetricsEMAAlpha;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = WorkerUtilizationAwareAssignmentConfig.class)
|
||||||
|
private Duration staleWorkerMetricsEntryCleanupDuration;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package software.amazon.kinesis.multilang.config.converter;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
import org.apache.commons.beanutils.Converter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converter that converts Duration text representation to a Duration object.
|
||||||
|
* Refer to {@code Duration.parse} javadocs for the exact text representation.
|
||||||
|
*/
|
||||||
|
public class DurationConverter implements Converter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T convert(Class<T> type, Object value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != Duration.class) {
|
||||||
|
throw new ConversionException("Can only convert to Duration");
|
||||||
|
}
|
||||||
|
|
||||||
|
String durationString = value.toString().trim();
|
||||||
|
final Duration duration = Duration.parse(durationString);
|
||||||
|
if (duration.isNegative()) {
|
||||||
|
throw new ConversionException("Negative values are not permitted for duration: " + durationString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return type.cast(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ConversionException extends RuntimeException {
|
||||||
|
public ConversionException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -157,7 +157,7 @@ public class MultiLangDaemonTest {
|
||||||
|
|
||||||
MultiLangDaemon.MultiLangDaemonArguments arguments = new MultiLangDaemon.MultiLangDaemonArguments();
|
MultiLangDaemon.MultiLangDaemonArguments arguments = new MultiLangDaemon.MultiLangDaemonArguments();
|
||||||
|
|
||||||
daemon.propertiesFile(arguments);
|
daemon.validateAndGetPropertiesFileName(arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -166,7 +166,7 @@ public class MultiLangDaemonTest {
|
||||||
MultiLangDaemon.MultiLangDaemonArguments arguments = new MultiLangDaemon.MultiLangDaemonArguments();
|
MultiLangDaemon.MultiLangDaemonArguments arguments = new MultiLangDaemon.MultiLangDaemonArguments();
|
||||||
arguments.parameters = Collections.singletonList(expectedPropertiesFile);
|
arguments.parameters = Collections.singletonList(expectedPropertiesFile);
|
||||||
|
|
||||||
String propertiesFile = daemon.propertiesFile(arguments);
|
String propertiesFile = daemon.validateAndGetPropertiesFileName(arguments);
|
||||||
|
|
||||||
assertThat(propertiesFile, equalTo(expectedPropertiesFile));
|
assertThat(propertiesFile, equalTo(expectedPropertiesFile));
|
||||||
}
|
}
|
||||||
|
|
@ -180,7 +180,7 @@ public class MultiLangDaemonTest {
|
||||||
arguments.parameters = Collections.singletonList(propertiesArgument);
|
arguments.parameters = Collections.singletonList(propertiesArgument);
|
||||||
arguments.propertiesFile = propertiesOptions;
|
arguments.propertiesFile = propertiesOptions;
|
||||||
|
|
||||||
String propertiesFile = daemon.propertiesFile(arguments);
|
String propertiesFile = daemon.validateAndGetPropertiesFileName(arguments);
|
||||||
|
|
||||||
assertThat(propertiesFile, equalTo(propertiesOptions));
|
assertThat(propertiesFile, equalTo(propertiesOptions));
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +193,7 @@ public class MultiLangDaemonTest {
|
||||||
MultiLangDaemon.MultiLangDaemonArguments arguments = new MultiLangDaemon.MultiLangDaemonArguments();
|
MultiLangDaemon.MultiLangDaemonArguments arguments = new MultiLangDaemon.MultiLangDaemonArguments();
|
||||||
arguments.parameters = Arrays.asList("parameter1", "parameter2");
|
arguments.parameters = Arrays.asList("parameter1", "parameter2");
|
||||||
|
|
||||||
daemon.propertiesFile(arguments);
|
daemon.validateAndGetPropertiesFileName(arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,16 @@ public class ConfigurationSettableUtilsTest {
|
||||||
assertThat(actual, equalTo(expected));
|
assertThat(actual, equalTo(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBoolean() {
|
||||||
|
ConfigResult expected = ConfigResult.builder().bool(false).build();
|
||||||
|
|
||||||
|
ConfigObject configObject = ConfigObject.builder().bool(expected.bool).build();
|
||||||
|
ConfigResult actual = resolve(configObject);
|
||||||
|
|
||||||
|
assertThat(actual, equalTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHeapValuesSet() {
|
public void testHeapValuesSet() {
|
||||||
ConfigResult expected =
|
ConfigResult expected =
|
||||||
|
|
@ -147,6 +157,9 @@ public class ConfigurationSettableUtilsTest {
|
||||||
private Long boxedLong;
|
private Long boxedLong;
|
||||||
private ComplexValue complexValue;
|
private ComplexValue complexValue;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
private Boolean bool = true;
|
||||||
|
|
||||||
private Optional<String> optionalString;
|
private Optional<String> optionalString;
|
||||||
private Optional<Integer> optionalInteger;
|
private Optional<Integer> optionalInteger;
|
||||||
private Optional<Long> optionalLong;
|
private Optional<Long> optionalLong;
|
||||||
|
|
@ -175,6 +188,10 @@ public class ConfigurationSettableUtilsTest {
|
||||||
@ConfigurationSettable(configurationClass = ConfigResult.class)
|
@ConfigurationSettable(configurationClass = ConfigResult.class)
|
||||||
private int rawInt;
|
private int rawInt;
|
||||||
|
|
||||||
|
@ConfigurationSettable(configurationClass = ConfigResult.class)
|
||||||
|
@Builder.Default
|
||||||
|
private Boolean bool = true;
|
||||||
|
|
||||||
@ConfigurationSettable(configurationClass = ConfigResult.class)
|
@ConfigurationSettable(configurationClass = ConfigResult.class)
|
||||||
private Integer boxedInt;
|
private Integer boxedInt;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import java.net.URI;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.amazonaws.auth.AWSCredentials;
|
import com.amazonaws.auth.AWSCredentials;
|
||||||
|
|
@ -32,7 +33,9 @@ import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
|
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
|
||||||
|
import software.amazon.awssdk.services.dynamodb.model.BillingMode;
|
||||||
import software.amazon.kinesis.common.InitialPositionInStream;
|
import software.amazon.kinesis.common.InitialPositionInStream;
|
||||||
|
import software.amazon.kinesis.coordinator.CoordinatorConfig;
|
||||||
import software.amazon.kinesis.metrics.MetricsLevel;
|
import software.amazon.kinesis.metrics.MetricsLevel;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
|
@ -40,6 +43,7 @@ import static org.hamcrest.CoreMatchers.nullValue;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
@ -69,6 +73,8 @@ public class KinesisClientLibConfiguratorTest {
|
||||||
assertEquals(config.getWorkerIdentifier(), "123");
|
assertEquals(config.getWorkerIdentifier(), "123");
|
||||||
assertThat(config.getMaxGetRecordsThreadPool(), nullValue());
|
assertThat(config.getMaxGetRecordsThreadPool(), nullValue());
|
||||||
assertThat(config.getRetryGetRecordsInSeconds(), nullValue());
|
assertThat(config.getRetryGetRecordsInSeconds(), nullValue());
|
||||||
|
assertNull(config.getGracefulLeaseHandoffTimeoutMillis());
|
||||||
|
assertNull(config.getIsGracefulLeaseHandoffEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -147,6 +153,151 @@ public class KinesisClientLibConfiguratorTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGracefulLeaseHandoffConfig() {
|
||||||
|
final Long testGracefulLeaseHandoffTimeoutMillis = 12345L;
|
||||||
|
final boolean testGracefulLeaseHandoffEnabled = true;
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration config = getConfiguration(StringUtils.join(
|
||||||
|
new String[] {
|
||||||
|
"applicationName = dummyApplicationName",
|
||||||
|
"streamName = dummyStreamName",
|
||||||
|
"AWSCredentialsProvider = " + credentialName1 + ", " + credentialName2,
|
||||||
|
"gracefulLeaseHandoffTimeoutMillis = " + testGracefulLeaseHandoffTimeoutMillis,
|
||||||
|
"isGracefulLeaseHandoffEnabled = " + testGracefulLeaseHandoffEnabled
|
||||||
|
},
|
||||||
|
'\n'));
|
||||||
|
|
||||||
|
assertEquals(testGracefulLeaseHandoffTimeoutMillis, config.getGracefulLeaseHandoffTimeoutMillis());
|
||||||
|
assertEquals(testGracefulLeaseHandoffEnabled, config.getIsGracefulLeaseHandoffEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClientVersionConfig() {
|
||||||
|
final CoordinatorConfig.ClientVersionConfig testClientVersionConfig = Arrays.stream(
|
||||||
|
CoordinatorConfig.ClientVersionConfig.values())
|
||||||
|
.findAny()
|
||||||
|
.orElseThrow(NoSuchElementException::new);
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration config = getConfiguration(StringUtils.join(
|
||||||
|
new String[] {
|
||||||
|
"applicationName = dummyApplicationName",
|
||||||
|
"streamName = dummyStreamName",
|
||||||
|
"AWSCredentialsProvider = " + credentialName1 + ", " + credentialName2,
|
||||||
|
"clientVersionConfig = " + testClientVersionConfig.name()
|
||||||
|
},
|
||||||
|
'\n'));
|
||||||
|
|
||||||
|
assertEquals(testClientVersionConfig, config.getClientVersionConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCoordinatorStateConfig() {
|
||||||
|
final String testCoordinatorStateTableName = "CoordState";
|
||||||
|
final BillingMode testCoordinatorStateBillingMode = BillingMode.PAY_PER_REQUEST;
|
||||||
|
final long testCoordinatorStateReadCapacity = 123;
|
||||||
|
final long testCoordinatorStateWriteCapacity = 123;
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration config = getConfiguration(StringUtils.join(
|
||||||
|
new String[] {
|
||||||
|
"applicationName = dummyApplicationName",
|
||||||
|
"streamName = dummyStreamName",
|
||||||
|
"AWSCredentialsProvider = " + credentialName1 + ", " + credentialName2,
|
||||||
|
"coordinatorStateTableName = " + testCoordinatorStateTableName,
|
||||||
|
"coordinatorStateBillingMode = " + testCoordinatorStateBillingMode.name(),
|
||||||
|
"coordinatorStateReadCapacity = " + testCoordinatorStateReadCapacity,
|
||||||
|
"coordinatorStateWriteCapacity = " + testCoordinatorStateWriteCapacity
|
||||||
|
},
|
||||||
|
'\n'));
|
||||||
|
|
||||||
|
assertEquals(testCoordinatorStateTableName, config.getCoordinatorStateTableName());
|
||||||
|
assertEquals(testCoordinatorStateBillingMode, config.getCoordinatorStateBillingMode());
|
||||||
|
assertEquals(testCoordinatorStateReadCapacity, config.getCoordinatorStateReadCapacity());
|
||||||
|
assertEquals(testCoordinatorStateWriteCapacity, config.getCoordinatorStateWriteCapacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWorkerUtilizationAwareAssignmentConfig() {
|
||||||
|
final long testInMemoryWorkerMetricsCaptureFrequencyMillis = 123;
|
||||||
|
final long testWorkerMetricsReporterFreqInMillis = 123;
|
||||||
|
final long testNoOfPersistedMetricsPerWorkerMetrics = 123;
|
||||||
|
final Boolean testDisableWorkerMetrics = true;
|
||||||
|
final double testMaxThroughputPerHostKBps = 123;
|
||||||
|
final long testDampeningPercentage = 12;
|
||||||
|
final long testReBalanceThresholdPercentage = 12;
|
||||||
|
final Boolean testAllowThroughputOvershoot = false;
|
||||||
|
final long testVarianceBalancingFrequency = 12;
|
||||||
|
final double testWorkerMetricsEMAAlpha = .123;
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration config = getConfiguration(StringUtils.join(
|
||||||
|
new String[] {
|
||||||
|
"applicationName = dummyApplicationName",
|
||||||
|
"streamName = dummyStreamName",
|
||||||
|
"AWSCredentialsProvider = " + credentialName1 + ", " + credentialName2,
|
||||||
|
"inMemoryWorkerMetricsCaptureFrequencyMillis = " + testInMemoryWorkerMetricsCaptureFrequencyMillis,
|
||||||
|
"workerMetricsReporterFreqInMillis = " + testWorkerMetricsReporterFreqInMillis,
|
||||||
|
"noOfPersistedMetricsPerWorkerMetrics = " + testNoOfPersistedMetricsPerWorkerMetrics,
|
||||||
|
"disableWorkerMetrics = " + testDisableWorkerMetrics,
|
||||||
|
"maxThroughputPerHostKBps = " + testMaxThroughputPerHostKBps,
|
||||||
|
"dampeningPercentage = " + testDampeningPercentage,
|
||||||
|
"reBalanceThresholdPercentage = " + testReBalanceThresholdPercentage,
|
||||||
|
"allowThroughputOvershoot = " + testAllowThroughputOvershoot,
|
||||||
|
"varianceBalancingFrequency = " + testVarianceBalancingFrequency,
|
||||||
|
"workerMetricsEMAAlpha = " + testWorkerMetricsEMAAlpha
|
||||||
|
},
|
||||||
|
'\n'));
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
testInMemoryWorkerMetricsCaptureFrequencyMillis,
|
||||||
|
config.getInMemoryWorkerMetricsCaptureFrequencyMillis());
|
||||||
|
assertEquals(testWorkerMetricsReporterFreqInMillis, config.getWorkerMetricsReporterFreqInMillis());
|
||||||
|
assertEquals(testNoOfPersistedMetricsPerWorkerMetrics, config.getNoOfPersistedMetricsPerWorkerMetrics());
|
||||||
|
assertEquals(testDisableWorkerMetrics, config.getDisableWorkerMetrics());
|
||||||
|
assertEquals(testMaxThroughputPerHostKBps, config.getMaxThroughputPerHostKBps(), 0.0001);
|
||||||
|
assertEquals(testDampeningPercentage, config.getDampeningPercentage());
|
||||||
|
assertEquals(testReBalanceThresholdPercentage, config.getReBalanceThresholdPercentage());
|
||||||
|
assertEquals(testAllowThroughputOvershoot, config.getAllowThroughputOvershoot());
|
||||||
|
assertEquals(testVarianceBalancingFrequency, config.getVarianceBalancingFrequency());
|
||||||
|
assertEquals(testWorkerMetricsEMAAlpha, config.getWorkerMetricsEMAAlpha(), 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWorkerMetricsConfig() {
|
||||||
|
final String testWorkerMetricsTableName = "CoordState";
|
||||||
|
final BillingMode testWorkerMetricsBillingMode = BillingMode.PROVISIONED;
|
||||||
|
final long testWorkerMetricsReadCapacity = 123;
|
||||||
|
final long testWorkerMetricsWriteCapacity = 123;
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration config = getConfiguration(StringUtils.join(
|
||||||
|
new String[] {
|
||||||
|
"applicationName = dummyApplicationName",
|
||||||
|
"streamName = dummyStreamName",
|
||||||
|
"AWSCredentialsProvider = " + credentialName1 + ", " + credentialName2,
|
||||||
|
"workerMetricsTableName = " + testWorkerMetricsTableName,
|
||||||
|
"workerMetricsBillingMode = " + testWorkerMetricsBillingMode.name(),
|
||||||
|
"workerMetricsReadCapacity = " + testWorkerMetricsReadCapacity,
|
||||||
|
"workerMetricsWriteCapacity = " + testWorkerMetricsWriteCapacity
|
||||||
|
},
|
||||||
|
'\n'));
|
||||||
|
|
||||||
|
assertEquals(testWorkerMetricsTableName, config.getWorkerMetricsTableName());
|
||||||
|
assertEquals(testWorkerMetricsBillingMode, config.getWorkerMetricsBillingMode());
|
||||||
|
assertEquals(testWorkerMetricsReadCapacity, config.getWorkerMetricsReadCapacity());
|
||||||
|
assertEquals(testWorkerMetricsWriteCapacity, config.getWorkerMetricsWriteCapacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testInvalidClientVersionConfig() {
|
||||||
|
getConfiguration(StringUtils.join(
|
||||||
|
new String[] {
|
||||||
|
"applicationName = dummyApplicationName",
|
||||||
|
"streamName = dummyStreamName",
|
||||||
|
"AWSCredentialsProvider = " + credentialName1 + ", " + credentialName2,
|
||||||
|
"clientVersionConfig = " + "invalid_client_version_config"
|
||||||
|
},
|
||||||
|
'\n'));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWithUnsupportedClientConfigurationVariables() {
|
public void testWithUnsupportedClientConfigurationVariables() {
|
||||||
MultiLangDaemonConfiguration config = getConfiguration(StringUtils.join(
|
MultiLangDaemonConfiguration config = getConfiguration(StringUtils.join(
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@
|
||||||
|
|
||||||
package software.amazon.kinesis.multilang.config;
|
package software.amazon.kinesis.multilang.config;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
import org.apache.commons.beanutils.BeanUtilsBean;
|
import org.apache.commons.beanutils.BeanUtilsBean;
|
||||||
import org.apache.commons.beanutils.ConvertUtilsBean;
|
import org.apache.commons.beanutils.ConvertUtilsBean;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
|
@ -24,8 +27,16 @@ import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
|
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
|
||||||
|
import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
|
||||||
|
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
||||||
|
import software.amazon.awssdk.services.dynamodb.model.BillingMode;
|
||||||
|
import software.amazon.awssdk.services.kinesis.KinesisAsyncClient;
|
||||||
|
import software.amazon.kinesis.common.ConfigsBuilder;
|
||||||
|
import software.amazon.kinesis.coordinator.CoordinatorConfig;
|
||||||
|
import software.amazon.kinesis.leases.LeaseManagementConfig;
|
||||||
import software.amazon.kinesis.processor.ShardRecordProcessorFactory;
|
import software.amazon.kinesis.processor.ShardRecordProcessorFactory;
|
||||||
import software.amazon.kinesis.retrieval.fanout.FanOutConfig;
|
import software.amazon.kinesis.retrieval.fanout.FanOutConfig;
|
||||||
import software.amazon.kinesis.retrieval.polling.PollingConfig;
|
import software.amazon.kinesis.retrieval.polling.PollingConfig;
|
||||||
|
|
@ -34,6 +45,7 @@ import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
|
@ -41,6 +53,8 @@ import static org.junit.Assert.assertTrue;
|
||||||
public class MultiLangDaemonConfigurationTest {
|
public class MultiLangDaemonConfigurationTest {
|
||||||
|
|
||||||
private static final String AWS_REGION_PROPERTY_NAME = "aws.region";
|
private static final String AWS_REGION_PROPERTY_NAME = "aws.region";
|
||||||
|
private static final String DUMMY_APPLICATION_NAME = "dummyApplicationName";
|
||||||
|
private static final String DUMMY_STREAM_NAME = "dummyStreamName";
|
||||||
|
|
||||||
private BeanUtilsBean utilsBean;
|
private BeanUtilsBean utilsBean;
|
||||||
private ConvertUtilsBean convertUtilsBean;
|
private ConvertUtilsBean convertUtilsBean;
|
||||||
|
|
@ -71,8 +85,8 @@ public class MultiLangDaemonConfigurationTest {
|
||||||
|
|
||||||
public MultiLangDaemonConfiguration baseConfiguration() {
|
public MultiLangDaemonConfiguration baseConfiguration() {
|
||||||
MultiLangDaemonConfiguration configuration = new MultiLangDaemonConfiguration(utilsBean, convertUtilsBean);
|
MultiLangDaemonConfiguration configuration = new MultiLangDaemonConfiguration(utilsBean, convertUtilsBean);
|
||||||
configuration.setApplicationName("Test");
|
configuration.setApplicationName(DUMMY_APPLICATION_NAME);
|
||||||
configuration.setStreamName("Test");
|
configuration.setStreamName(DUMMY_STREAM_NAME);
|
||||||
configuration.getKinesisCredentialsProvider().set("class", DefaultCredentialsProvider.class.getName());
|
configuration.getKinesisCredentialsProvider().set("class", DefaultCredentialsProvider.class.getName());
|
||||||
|
|
||||||
return configuration;
|
return configuration;
|
||||||
|
|
@ -111,6 +125,197 @@ public class MultiLangDaemonConfigurationTest {
|
||||||
assertTrue(resolvedConfiguration.leaseManagementConfig.leaseTableDeletionProtectionEnabled());
|
assertTrue(resolvedConfiguration.leaseManagementConfig.leaseTableDeletionProtectionEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGracefulLeaseHandoffConfig() {
|
||||||
|
final LeaseManagementConfig.GracefulLeaseHandoffConfig defaultGracefulLeaseHandoffConfig =
|
||||||
|
getTestConfigsBuilder().leaseManagementConfig().gracefulLeaseHandoffConfig();
|
||||||
|
|
||||||
|
final long testGracefulLeaseHandoffTimeoutMillis =
|
||||||
|
defaultGracefulLeaseHandoffConfig.gracefulLeaseHandoffTimeoutMillis() + 12345;
|
||||||
|
final boolean testGracefulLeaseHandoffEnabled =
|
||||||
|
!defaultGracefulLeaseHandoffConfig.isGracefulLeaseHandoffEnabled();
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration configuration = baseConfiguration();
|
||||||
|
configuration.setGracefulLeaseHandoffTimeoutMillis(testGracefulLeaseHandoffTimeoutMillis);
|
||||||
|
configuration.setIsGracefulLeaseHandoffEnabled(testGracefulLeaseHandoffEnabled);
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration.ResolvedConfiguration resolvedConfiguration =
|
||||||
|
configuration.resolvedConfiguration(shardRecordProcessorFactory);
|
||||||
|
|
||||||
|
final LeaseManagementConfig.GracefulLeaseHandoffConfig gracefulLeaseHandoffConfig =
|
||||||
|
resolvedConfiguration.leaseManagementConfig.gracefulLeaseHandoffConfig();
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
testGracefulLeaseHandoffTimeoutMillis, gracefulLeaseHandoffConfig.gracefulLeaseHandoffTimeoutMillis());
|
||||||
|
assertEquals(testGracefulLeaseHandoffEnabled, gracefulLeaseHandoffConfig.isGracefulLeaseHandoffEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGracefulLeaseHandoffUsesDefaults() {
|
||||||
|
final MultiLangDaemonConfiguration.ResolvedConfiguration resolvedConfiguration =
|
||||||
|
baseConfiguration().resolvedConfiguration(shardRecordProcessorFactory);
|
||||||
|
|
||||||
|
final LeaseManagementConfig.GracefulLeaseHandoffConfig gracefulLeaseHandoffConfig =
|
||||||
|
resolvedConfiguration.leaseManagementConfig.gracefulLeaseHandoffConfig();
|
||||||
|
|
||||||
|
final LeaseManagementConfig.GracefulLeaseHandoffConfig defaultGracefulLeaseHandoffConfig =
|
||||||
|
getTestConfigsBuilder().leaseManagementConfig().gracefulLeaseHandoffConfig();
|
||||||
|
|
||||||
|
assertEquals(defaultGracefulLeaseHandoffConfig, gracefulLeaseHandoffConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWorkerUtilizationAwareAssignmentConfig() {
|
||||||
|
MultiLangDaemonConfiguration configuration = baseConfiguration();
|
||||||
|
|
||||||
|
configuration.setInMemoryWorkerMetricsCaptureFrequencyMillis(123);
|
||||||
|
configuration.setWorkerMetricsReporterFreqInMillis(123);
|
||||||
|
configuration.setNoOfPersistedMetricsPerWorkerMetrics(123);
|
||||||
|
configuration.setDisableWorkerMetrics(true);
|
||||||
|
configuration.setMaxThroughputPerHostKBps(.123);
|
||||||
|
configuration.setDampeningPercentage(12);
|
||||||
|
configuration.setReBalanceThresholdPercentage(12);
|
||||||
|
configuration.setAllowThroughputOvershoot(false);
|
||||||
|
configuration.setVarianceBalancingFrequency(12);
|
||||||
|
configuration.setWorkerMetricsEMAAlpha(.123);
|
||||||
|
|
||||||
|
MultiLangDaemonConfiguration.ResolvedConfiguration resolvedConfiguration =
|
||||||
|
configuration.resolvedConfiguration(shardRecordProcessorFactory);
|
||||||
|
LeaseManagementConfig leaseManagementConfig = resolvedConfiguration.leaseManagementConfig;
|
||||||
|
LeaseManagementConfig.WorkerUtilizationAwareAssignmentConfig config =
|
||||||
|
leaseManagementConfig.workerUtilizationAwareAssignmentConfig();
|
||||||
|
|
||||||
|
assertEquals(config.inMemoryWorkerMetricsCaptureFrequencyMillis(), 123);
|
||||||
|
assertEquals(config.workerMetricsReporterFreqInMillis(), 123);
|
||||||
|
assertEquals(config.noOfPersistedMetricsPerWorkerMetrics(), 123);
|
||||||
|
assertTrue(config.disableWorkerMetrics());
|
||||||
|
assertEquals(config.maxThroughputPerHostKBps(), .123, .25);
|
||||||
|
assertEquals(config.dampeningPercentage(), 12);
|
||||||
|
assertEquals(config.reBalanceThresholdPercentage(), 12);
|
||||||
|
assertFalse(config.allowThroughputOvershoot());
|
||||||
|
assertEquals(config.varianceBalancingFrequency(), 12);
|
||||||
|
assertEquals(config.workerMetricsEMAAlpha(), .123, .25);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWorkerUtilizationAwareAssignmentConfigUsesDefaults() {
|
||||||
|
final LeaseManagementConfig.WorkerUtilizationAwareAssignmentConfig defaultWorkerUtilAwareAssignmentConfig =
|
||||||
|
getTestConfigsBuilder().leaseManagementConfig().workerUtilizationAwareAssignmentConfig();
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration configuration = baseConfiguration();
|
||||||
|
configuration.setVarianceBalancingFrequency(
|
||||||
|
defaultWorkerUtilAwareAssignmentConfig.varianceBalancingFrequency() + 12345);
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration.ResolvedConfiguration resolvedConfiguration =
|
||||||
|
configuration.resolvedConfiguration(shardRecordProcessorFactory);
|
||||||
|
|
||||||
|
final LeaseManagementConfig.WorkerUtilizationAwareAssignmentConfig resolvedWorkerUtilAwareAssignmentConfig =
|
||||||
|
resolvedConfiguration.leaseManagementConfig.workerUtilizationAwareAssignmentConfig();
|
||||||
|
|
||||||
|
assertNotEquals(defaultWorkerUtilAwareAssignmentConfig, resolvedWorkerUtilAwareAssignmentConfig);
|
||||||
|
|
||||||
|
// apart from the single updated configuration, all other config values should be equal to the default
|
||||||
|
resolvedWorkerUtilAwareAssignmentConfig.varianceBalancingFrequency(
|
||||||
|
defaultWorkerUtilAwareAssignmentConfig.varianceBalancingFrequency());
|
||||||
|
assertEquals(defaultWorkerUtilAwareAssignmentConfig, resolvedWorkerUtilAwareAssignmentConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWorkerMetricsTableConfigBean() {
|
||||||
|
final BillingMode testWorkerMetricsTableBillingMode = BillingMode.PROVISIONED;
|
||||||
|
|
||||||
|
MultiLangDaemonConfiguration configuration = baseConfiguration();
|
||||||
|
|
||||||
|
configuration.setWorkerMetricsTableName("testTable");
|
||||||
|
configuration.setWorkerMetricsBillingMode(testWorkerMetricsTableBillingMode);
|
||||||
|
configuration.setWorkerMetricsReadCapacity(123);
|
||||||
|
configuration.setWorkerMetricsWriteCapacity(123);
|
||||||
|
|
||||||
|
MultiLangDaemonConfiguration.ResolvedConfiguration resolvedConfiguration =
|
||||||
|
configuration.resolvedConfiguration(shardRecordProcessorFactory);
|
||||||
|
LeaseManagementConfig leaseManagementConfig = resolvedConfiguration.leaseManagementConfig;
|
||||||
|
LeaseManagementConfig.WorkerUtilizationAwareAssignmentConfig workerUtilizationConfig =
|
||||||
|
leaseManagementConfig.workerUtilizationAwareAssignmentConfig();
|
||||||
|
LeaseManagementConfig.WorkerMetricsTableConfig workerMetricsConfig =
|
||||||
|
workerUtilizationConfig.workerMetricsTableConfig();
|
||||||
|
|
||||||
|
assertEquals(workerMetricsConfig.tableName(), "testTable");
|
||||||
|
assertEquals(workerMetricsConfig.billingMode(), testWorkerMetricsTableBillingMode);
|
||||||
|
assertEquals(workerMetricsConfig.readCapacity(), 123);
|
||||||
|
assertEquals(workerMetricsConfig.writeCapacity(), 123);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWorkerMetricsTableConfigUsesDefaults() {
|
||||||
|
final LeaseManagementConfig.WorkerMetricsTableConfig defaultWorkerMetricsTableConfig = getTestConfigsBuilder()
|
||||||
|
.leaseManagementConfig()
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.workerMetricsTableConfig();
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration configuration = baseConfiguration();
|
||||||
|
configuration.setWorkerMetricsBillingMode(Arrays.stream(BillingMode.values())
|
||||||
|
.filter(billingMode -> billingMode != defaultWorkerMetricsTableConfig.billingMode())
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(NoSuchElementException::new));
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration.ResolvedConfiguration resolvedConfiguration =
|
||||||
|
configuration.resolvedConfiguration(shardRecordProcessorFactory);
|
||||||
|
|
||||||
|
final LeaseManagementConfig.WorkerMetricsTableConfig resolvedWorkerMetricsTableConfig = resolvedConfiguration
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.workerMetricsTableConfig();
|
||||||
|
|
||||||
|
assertNotEquals(defaultWorkerMetricsTableConfig, resolvedWorkerMetricsTableConfig);
|
||||||
|
|
||||||
|
// apart from the single updated configuration, all other config values should be equal to the default
|
||||||
|
resolvedWorkerMetricsTableConfig.billingMode(defaultWorkerMetricsTableConfig.billingMode());
|
||||||
|
assertEquals(defaultWorkerMetricsTableConfig, resolvedWorkerMetricsTableConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCoordinatorStateTableConfigBean() {
|
||||||
|
final BillingMode testWorkerMetricsTableBillingMode = BillingMode.PAY_PER_REQUEST;
|
||||||
|
|
||||||
|
MultiLangDaemonConfiguration configuration = baseConfiguration();
|
||||||
|
|
||||||
|
configuration.setCoordinatorStateTableName("testTable");
|
||||||
|
configuration.setCoordinatorStateBillingMode(testWorkerMetricsTableBillingMode);
|
||||||
|
configuration.setCoordinatorStateReadCapacity(123);
|
||||||
|
configuration.setCoordinatorStateWriteCapacity(123);
|
||||||
|
|
||||||
|
MultiLangDaemonConfiguration.ResolvedConfiguration resolvedConfiguration =
|
||||||
|
configuration.resolvedConfiguration(shardRecordProcessorFactory);
|
||||||
|
CoordinatorConfig coordinatorConfig = resolvedConfiguration.getCoordinatorConfig();
|
||||||
|
CoordinatorConfig.CoordinatorStateTableConfig coordinatorStateConfig =
|
||||||
|
coordinatorConfig.coordinatorStateConfig();
|
||||||
|
assertEquals(coordinatorStateConfig.tableName(), "testTable");
|
||||||
|
assertEquals(coordinatorStateConfig.billingMode(), testWorkerMetricsTableBillingMode);
|
||||||
|
assertEquals(coordinatorStateConfig.readCapacity(), 123);
|
||||||
|
assertEquals(coordinatorStateConfig.writeCapacity(), 123);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCoordinatorStateTableConfigUsesDefaults() {
|
||||||
|
final CoordinatorConfig.CoordinatorStateTableConfig defaultCoordinatorStateTableConfig =
|
||||||
|
getTestConfigsBuilder().coordinatorConfig().coordinatorStateConfig();
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration configuration = baseConfiguration();
|
||||||
|
configuration.setCoordinatorStateWriteCapacity(defaultCoordinatorStateTableConfig.writeCapacity() + 12345);
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration.ResolvedConfiguration resolvedConfiguration =
|
||||||
|
configuration.resolvedConfiguration(shardRecordProcessorFactory);
|
||||||
|
|
||||||
|
final CoordinatorConfig.CoordinatorStateTableConfig resolvedCoordinatorStateTableConfig =
|
||||||
|
resolvedConfiguration.coordinatorConfig.coordinatorStateConfig();
|
||||||
|
|
||||||
|
assertNotEquals(defaultCoordinatorStateTableConfig, resolvedCoordinatorStateTableConfig);
|
||||||
|
|
||||||
|
// apart from the single updated configuration, all other config values should be equal to the default
|
||||||
|
resolvedCoordinatorStateTableConfig.writeCapacity(defaultCoordinatorStateTableConfig.writeCapacity());
|
||||||
|
assertEquals(defaultCoordinatorStateTableConfig, resolvedCoordinatorStateTableConfig);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetLeaseTablePitrEnabledToTrue() {
|
public void testSetLeaseTablePitrEnabledToTrue() {
|
||||||
MultiLangDaemonConfiguration configuration = baseConfiguration();
|
MultiLangDaemonConfiguration configuration = baseConfiguration();
|
||||||
|
|
@ -266,4 +471,43 @@ public class MultiLangDaemonConfigurationTest {
|
||||||
|
|
||||||
assertThat(fanOutConfig.consumerArn(), equalTo(consumerArn));
|
assertThat(fanOutConfig.consumerArn(), equalTo(consumerArn));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClientVersionConfig() {
|
||||||
|
final CoordinatorConfig.ClientVersionConfig testClientVersionConfig =
|
||||||
|
CoordinatorConfig.ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X;
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration configuration = baseConfiguration();
|
||||||
|
configuration.setClientVersionConfig(testClientVersionConfig);
|
||||||
|
|
||||||
|
final MultiLangDaemonConfiguration.ResolvedConfiguration resolvedConfiguration =
|
||||||
|
configuration.resolvedConfiguration(shardRecordProcessorFactory);
|
||||||
|
|
||||||
|
final CoordinatorConfig coordinatorConfig = resolvedConfiguration.coordinatorConfig;
|
||||||
|
|
||||||
|
assertEquals(testClientVersionConfig, coordinatorConfig.clientVersionConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClientVersionConfigUsesDefault() {
|
||||||
|
final MultiLangDaemonConfiguration.ResolvedConfiguration resolvedConfiguration =
|
||||||
|
baseConfiguration().resolvedConfiguration(shardRecordProcessorFactory);
|
||||||
|
|
||||||
|
final CoordinatorConfig coordinatorConfig = resolvedConfiguration.coordinatorConfig;
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
getTestConfigsBuilder().coordinatorConfig().clientVersionConfig(),
|
||||||
|
coordinatorConfig.clientVersionConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConfigsBuilder getTestConfigsBuilder() {
|
||||||
|
return new ConfigsBuilder(
|
||||||
|
DUMMY_STREAM_NAME,
|
||||||
|
DUMMY_APPLICATION_NAME,
|
||||||
|
Mockito.mock(KinesisAsyncClient.class),
|
||||||
|
Mockito.mock(DynamoDbAsyncClient.class),
|
||||||
|
Mockito.mock(CloudWatchAsyncClient.class),
|
||||||
|
"dummyWorkerIdentifier",
|
||||||
|
shardRecordProcessorFactory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,249 @@
|
||||||
|
package software.amazon.kinesis.multilang.config;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import software.amazon.awssdk.services.dynamodb.model.BillingMode;
|
||||||
|
import software.amazon.kinesis.coordinator.CoordinatorConfig.ClientVersionConfig;
|
||||||
|
import software.amazon.kinesis.multilang.MultiLangDaemonConfig;
|
||||||
|
import software.amazon.kinesis.multilang.config.MultiLangDaemonConfiguration.ResolvedConfiguration;
|
||||||
|
import software.amazon.kinesis.processor.ShardRecordProcessor;
|
||||||
|
import software.amazon.kinesis.processor.ShardRecordProcessorFactory;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
public class PropertiesMappingE2ETest {
|
||||||
|
private static final String PROPERTIES_FILE = "multilang.properties";
|
||||||
|
private static final String PROPERTIES_FILE_V3 = "multilangv3.properties";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKclV3PropertiesMapping() throws IOException {
|
||||||
|
final MultiLangDaemonConfig config = new MultiLangDaemonConfig(PROPERTIES_FILE);
|
||||||
|
|
||||||
|
final ResolvedConfiguration kclV3Config =
|
||||||
|
config.getMultiLangDaemonConfiguration().resolvedConfiguration(new TestRecordProcessorFactory());
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X,
|
||||||
|
kclV3Config.coordinatorConfig.clientVersionConfig());
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"MultiLangTest-CoordinatorState-CustomName",
|
||||||
|
kclV3Config.coordinatorConfig.coordinatorStateConfig().tableName());
|
||||||
|
assertEquals(
|
||||||
|
BillingMode.PROVISIONED,
|
||||||
|
kclV3Config.coordinatorConfig.coordinatorStateConfig().billingMode());
|
||||||
|
assertEquals(
|
||||||
|
1000, kclV3Config.coordinatorConfig.coordinatorStateConfig().readCapacity());
|
||||||
|
assertEquals(500, kclV3Config.coordinatorConfig.coordinatorStateConfig().writeCapacity());
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
10000L,
|
||||||
|
kclV3Config.leaseManagementConfig.gracefulLeaseHandoffConfig().gracefulLeaseHandoffTimeoutMillis());
|
||||||
|
assertFalse(
|
||||||
|
kclV3Config.leaseManagementConfig.gracefulLeaseHandoffConfig().isGracefulLeaseHandoffEnabled());
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
5000L,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.inMemoryWorkerMetricsCaptureFrequencyMillis());
|
||||||
|
assertEquals(
|
||||||
|
60000L,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.workerMetricsReporterFreqInMillis());
|
||||||
|
assertEquals(
|
||||||
|
50,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.noOfPersistedMetricsPerWorkerMetrics());
|
||||||
|
assertTrue(kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.disableWorkerMetrics());
|
||||||
|
assertEquals(
|
||||||
|
10000,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.maxThroughputPerHostKBps());
|
||||||
|
assertEquals(
|
||||||
|
90,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.dampeningPercentage());
|
||||||
|
assertEquals(
|
||||||
|
5,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.reBalanceThresholdPercentage());
|
||||||
|
assertFalse(kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.allowThroughputOvershoot());
|
||||||
|
assertEquals(
|
||||||
|
Duration.ofHours(12),
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.staleWorkerMetricsEntryCleanupDuration());
|
||||||
|
assertEquals(
|
||||||
|
5,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.varianceBalancingFrequency());
|
||||||
|
assertEquals(
|
||||||
|
0.18D,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.workerMetricsEMAAlpha());
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"MultiLangTest-WorkerMetrics-CustomName",
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.workerMetricsTableConfig()
|
||||||
|
.tableName());
|
||||||
|
assertEquals(
|
||||||
|
BillingMode.PROVISIONED,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.workerMetricsTableConfig()
|
||||||
|
.billingMode());
|
||||||
|
assertEquals(
|
||||||
|
250,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.workerMetricsTableConfig()
|
||||||
|
.readCapacity());
|
||||||
|
assertEquals(
|
||||||
|
90,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.workerMetricsTableConfig()
|
||||||
|
.writeCapacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKclV3PropertiesMappingForDefaultValues() throws IOException {
|
||||||
|
final MultiLangDaemonConfig config = new MultiLangDaemonConfig(PROPERTIES_FILE_V3);
|
||||||
|
|
||||||
|
final ResolvedConfiguration kclV3Config =
|
||||||
|
config.getMultiLangDaemonConfiguration().resolvedConfiguration(new TestRecordProcessorFactory());
|
||||||
|
|
||||||
|
assertEquals(ClientVersionConfig.CLIENT_VERSION_CONFIG_3X, kclV3Config.coordinatorConfig.clientVersionConfig());
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"MultiLangTest-CoordinatorState",
|
||||||
|
kclV3Config.coordinatorConfig.coordinatorStateConfig().tableName());
|
||||||
|
assertEquals(
|
||||||
|
BillingMode.PAY_PER_REQUEST,
|
||||||
|
kclV3Config.coordinatorConfig.coordinatorStateConfig().billingMode());
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
30_000L,
|
||||||
|
kclV3Config.leaseManagementConfig.gracefulLeaseHandoffConfig().gracefulLeaseHandoffTimeoutMillis());
|
||||||
|
assertTrue(
|
||||||
|
kclV3Config.leaseManagementConfig.gracefulLeaseHandoffConfig().isGracefulLeaseHandoffEnabled());
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
1000L,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.inMemoryWorkerMetricsCaptureFrequencyMillis());
|
||||||
|
assertEquals(
|
||||||
|
30000L,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.workerMetricsReporterFreqInMillis());
|
||||||
|
assertEquals(
|
||||||
|
10,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.noOfPersistedMetricsPerWorkerMetrics());
|
||||||
|
assertFalse(kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.disableWorkerMetrics());
|
||||||
|
assertEquals(
|
||||||
|
Double.MAX_VALUE,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.maxThroughputPerHostKBps());
|
||||||
|
assertEquals(
|
||||||
|
60,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.dampeningPercentage());
|
||||||
|
assertEquals(
|
||||||
|
10,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.reBalanceThresholdPercentage());
|
||||||
|
assertTrue(kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.allowThroughputOvershoot());
|
||||||
|
assertEquals(
|
||||||
|
Duration.ofDays(1),
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.staleWorkerMetricsEntryCleanupDuration());
|
||||||
|
assertEquals(
|
||||||
|
3,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.varianceBalancingFrequency());
|
||||||
|
assertEquals(
|
||||||
|
0.5D,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.workerMetricsEMAAlpha());
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"MultiLangTest-WorkerMetricStats",
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.workerMetricsTableConfig()
|
||||||
|
.tableName());
|
||||||
|
assertEquals(
|
||||||
|
BillingMode.PAY_PER_REQUEST,
|
||||||
|
kclV3Config
|
||||||
|
.leaseManagementConfig
|
||||||
|
.workerUtilizationAwareAssignmentConfig()
|
||||||
|
.workerMetricsTableConfig()
|
||||||
|
.billingMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TestRecordProcessorFactory implements ShardRecordProcessorFactory {
|
||||||
|
@Override
|
||||||
|
public ShardRecordProcessor shardRecordProcessor() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Amazon.com, Inc. or its affiliates.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package software.amazon.kinesis.multilang.config;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.apache.commons.beanutils.BeanUtilsBean;
|
||||||
|
import org.apache.commons.beanutils.ConvertUtilsBean;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
import software.amazon.awssdk.services.kinesis.KinesisAsyncClient;
|
||||||
|
import software.amazon.kinesis.retrieval.polling.PollingConfig;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class WorkerUtilizationAwareAssignmentConfigBeanTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private KinesisAsyncClient kinesisAsyncClient;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAllPropertiesTransit() {
|
||||||
|
PollingConfigBean pollingConfigBean = new PollingConfigBean();
|
||||||
|
pollingConfigBean.setIdleTimeBetweenReadsInMillis(1000);
|
||||||
|
pollingConfigBean.setMaxGetRecordsThreadPool(20);
|
||||||
|
pollingConfigBean.setMaxRecords(5000);
|
||||||
|
pollingConfigBean.setRetryGetRecordsInSeconds(30);
|
||||||
|
|
||||||
|
ConvertUtilsBean convertUtilsBean = new ConvertUtilsBean();
|
||||||
|
BeanUtilsBean utilsBean = new BeanUtilsBean(convertUtilsBean);
|
||||||
|
|
||||||
|
MultiLangDaemonConfiguration multiLangDaemonConfiguration =
|
||||||
|
new MultiLangDaemonConfiguration(utilsBean, convertUtilsBean);
|
||||||
|
multiLangDaemonConfiguration.setStreamName("test-stream");
|
||||||
|
|
||||||
|
PollingConfig pollingConfig = pollingConfigBean.build(kinesisAsyncClient, multiLangDaemonConfiguration);
|
||||||
|
|
||||||
|
assertThat(pollingConfig.kinesisClient(), equalTo(kinesisAsyncClient));
|
||||||
|
assertThat(pollingConfig.streamName(), equalTo(multiLangDaemonConfiguration.getStreamName()));
|
||||||
|
assertThat(
|
||||||
|
pollingConfig.idleTimeBetweenReadsInMillis(),
|
||||||
|
equalTo(pollingConfigBean.getIdleTimeBetweenReadsInMillis()));
|
||||||
|
assertThat(
|
||||||
|
pollingConfig.maxGetRecordsThreadPool(),
|
||||||
|
equalTo(Optional.of(pollingConfigBean.getMaxGetRecordsThreadPool())));
|
||||||
|
assertThat(pollingConfig.maxRecords(), equalTo(pollingConfigBean.getMaxRecords()));
|
||||||
|
assertThat(
|
||||||
|
pollingConfig.retryGetRecordsInSeconds(),
|
||||||
|
equalTo(Optional.of(pollingConfigBean.getRetryGetRecordsInSeconds())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -91,3 +91,73 @@ validateSequenceNumberBeforeCheckpointing = true
|
||||||
# active threads set to the provided value. If a non-positive integer or no
|
# active threads set to the provided value. If a non-positive integer or no
|
||||||
# value is provided a CachedThreadPool is used.
|
# value is provided a CachedThreadPool is used.
|
||||||
maxActiveThreads = -1
|
maxActiveThreads = -1
|
||||||
|
|
||||||
|
################### KclV3 configurations ###################
|
||||||
|
# Coordinator config
|
||||||
|
# Version the KCL needs to operate in. For more details check the KCLv3 migration
|
||||||
|
# documentation. Default is CLIENT_VERSION_CONFIG_3X
|
||||||
|
clientVersionConfig = CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2x
|
||||||
|
# TODO: include table deletion protection and pitr config once its added
|
||||||
|
# Configurations to control how the CoordinatorState DDB table is created
|
||||||
|
# Default name is applicationName-CoordinatorState in PAY_PER_REQUEST
|
||||||
|
coordinatorStateTableName = MultiLangTest-CoordinatorState-CustomName
|
||||||
|
coordinatorStateBillingMode = PROVISIONED
|
||||||
|
coordinatorStateReadCapacity = 1000
|
||||||
|
coordinatorStateWriteCapacity = 500
|
||||||
|
|
||||||
|
# Graceful handoff config - tuning of the shutdown behavior during lease transfers
|
||||||
|
# default values are 30000 and true respectively
|
||||||
|
gracefulLeaseHandoffTimeoutMillis = 10000
|
||||||
|
isGracefulLeaseHandoffEnabled = false
|
||||||
|
|
||||||
|
# WorkerMetricStats table config - control how the DDB table is created
|
||||||
|
## Default name is applicationName-WorkerMetricStats in PAY_PER_REQUEST
|
||||||
|
# TODO: include table deletion protection and pitr config once its added
|
||||||
|
workerMetricsTableName = MultiLangTest-WorkerMetrics-CustomName
|
||||||
|
workerMetricsBillingMode = PROVISIONED
|
||||||
|
workerMetricsReadCapacity = 250
|
||||||
|
workerMetricsWriteCapacity = 90
|
||||||
|
|
||||||
|
# WorkerUtilizationAwareAssignment config - tune the new KCLv3 Lease balancing algorithm
|
||||||
|
#
|
||||||
|
# frequency of capturing worker metrics in memory. Default is 1s
|
||||||
|
inMemoryWorkerMetricsCaptureFrequencyMillis = 5000
|
||||||
|
# frequency of reporting worker metric stats to storage. Default is 30s
|
||||||
|
workerMetricsReporterFreqInMillis = 60000
|
||||||
|
# No. of metricStats that are persisted in WorkerMetricStats ddb table, default is 10
|
||||||
|
noOfPersistedMetricsPerWorkerMetrics = 50
|
||||||
|
# Disable use of worker metrics to balance lease, default is false.
|
||||||
|
# If it is true, the algorithm balances lease based on worker's processing throughput.
|
||||||
|
disableWorkerMetrics = true
|
||||||
|
# Max throughput per host 10 MBps, to limit processing to the given value
|
||||||
|
# Default is unlimited.
|
||||||
|
maxThroughputPerHostKBps = 10000
|
||||||
|
# Dampen the load that is rebalanced during lease re-balancing, default is 60%
|
||||||
|
dampeningPercentage = 90
|
||||||
|
# Configures the allowed variance range for worker utilization. The upper
|
||||||
|
# limit is calculated as average * (1 + reBalanceThresholdPercentage/100).
|
||||||
|
# The lower limit is average * (1 - reBalanceThresholdPercentage/100). If
|
||||||
|
# any worker's utilization falls outside this range, lease re-balancing is
|
||||||
|
# triggered. The re-balancing algorithm aims to bring variance within the
|
||||||
|
# specified range. It also avoids thrashing by ensuring the utilization of
|
||||||
|
# the worker receiving the load after re-balancing doesn't exceed the fleet
|
||||||
|
# average. This might cause no re-balancing action even the utilization is
|
||||||
|
# out of the variance range. The default value is 10, representing +/-10%
|
||||||
|
# variance from the average value.
|
||||||
|
reBalanceThresholdPercentage = 5
|
||||||
|
# Whether at-least one lease must be taken from a high utilization worker
|
||||||
|
# during re-balancing when there is no lease assigned to that worker which has
|
||||||
|
# throughput is less than or equal to the minimum throughput that needs to be
|
||||||
|
# moved away from that worker to bring the worker back into the allowed variance.
|
||||||
|
# Default is true.
|
||||||
|
allowThroughputOvershoot = false
|
||||||
|
# Lease assignment is performed every failoverTimeMillis but re-balance will
|
||||||
|
# be attempted only once in 5 times based on the below config. Default is 3.
|
||||||
|
varianceBalancingFrequency = 5
|
||||||
|
# Alpha value used for calculating exponential moving average of worker's metricStats.
|
||||||
|
workerMetricsEMAAlpha = 0.18
|
||||||
|
# Duration after which workerMetricStats entry from WorkerMetricStats table will
|
||||||
|
# be cleaned up.
|
||||||
|
# Duration format examples: PT15M (15 mins) PT10H (10 hours) P2D (2 days)
|
||||||
|
# Refer to Duration.parse javadocs for more details
|
||||||
|
staleWorkerMetricsEntryCleanupDuration = PT12H
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,167 @@
|
||||||
|
# The script that abides by the multi-language protocol. This script will
|
||||||
|
# be executed by the MultiLangDaemon, which will communicate with this script
|
||||||
|
# over STDIN and STDOUT according to the multi-language protocol.
|
||||||
|
executableName = sample_kclpy_app.py
|
||||||
|
|
||||||
|
# The Stream arn: arn:aws:kinesis:<region>:<account id>:stream/<stream name>
|
||||||
|
# Important: streamArn takes precedence over streamName if both are set
|
||||||
|
streamArn = arn:aws:kinesis:us-east-5:000000000000:stream/kclpysample
|
||||||
|
|
||||||
|
# The name of an Amazon Kinesis stream to process.
|
||||||
|
# Important: streamArn takes precedence over streamName if both are set
|
||||||
|
streamName = kclpysample
|
||||||
|
|
||||||
|
# Used by the KCL as the name of this application. Will be used as the name
|
||||||
|
# of an Amazon DynamoDB table which will store the lease and checkpoint
|
||||||
|
# information for workers with this application name
|
||||||
|
applicationName = MultiLangTest
|
||||||
|
|
||||||
|
# Users can change the credentials provider the KCL will use to retrieve credentials.
|
||||||
|
# The DefaultAWSCredentialsProviderChain checks several other providers, which is
|
||||||
|
# described here:
|
||||||
|
# http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html
|
||||||
|
AWSCredentialsProvider = DefaultAWSCredentialsProviderChain
|
||||||
|
|
||||||
|
# Appended to the user agent of the KCL. Does not impact the functionality of the
|
||||||
|
# KCL in any other way.
|
||||||
|
processingLanguage = python/3.8
|
||||||
|
|
||||||
|
# Valid options at TRIM_HORIZON or LATEST.
|
||||||
|
# See http://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html#API_GetShardIterator_RequestSyntax
|
||||||
|
initialPositionInStream = TRIM_HORIZON
|
||||||
|
|
||||||
|
# To specify an initial timestamp from which to start processing records, please specify timestamp value for 'initiatPositionInStreamExtended',
|
||||||
|
# and uncomment below line with right timestamp value.
|
||||||
|
# See more from 'Timestamp' under http://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html#API_GetShardIterator_RequestSyntax
|
||||||
|
#initialPositionInStreamExtended = 1636609142
|
||||||
|
|
||||||
|
# The following properties are also available for configuring the KCL Worker that is created
|
||||||
|
# by the MultiLangDaemon.
|
||||||
|
|
||||||
|
# The KCL defaults to us-east-1
|
||||||
|
regionName = us-east-1
|
||||||
|
|
||||||
|
# Fail over time in milliseconds. A worker which does not renew it's lease within this time interval
|
||||||
|
# will be regarded as having problems and it's shards will be assigned to other workers.
|
||||||
|
# For applications that have a large number of shards, this msy be set to a higher number to reduce
|
||||||
|
# the number of DynamoDB IOPS required for tracking leases
|
||||||
|
failoverTimeMillis = 10000
|
||||||
|
|
||||||
|
# A worker id that uniquely identifies this worker among all workers using the same applicationName
|
||||||
|
# If this isn't provided a MultiLangDaemon instance will assign a unique workerId to itself.
|
||||||
|
workerId = "workerId"
|
||||||
|
|
||||||
|
# Shard sync interval in milliseconds - e.g. wait for this long between shard sync tasks.
|
||||||
|
shardSyncIntervalMillis = 60000
|
||||||
|
|
||||||
|
# Max records to fetch from Kinesis in a single GetRecords call.
|
||||||
|
maxRecords = 10000
|
||||||
|
|
||||||
|
# Idle time between record reads in milliseconds.
|
||||||
|
idleTimeBetweenReadsInMillis = 1000
|
||||||
|
|
||||||
|
# Enables applications flush/checkpoint (if they have some data "in progress", but don't get new data for while)
|
||||||
|
callProcessRecordsEvenForEmptyRecordList = false
|
||||||
|
|
||||||
|
# Interval in milliseconds between polling to check for parent shard completion.
|
||||||
|
# Polling frequently will take up more DynamoDB IOPS (when there are leases for shards waiting on
|
||||||
|
# completion of parent shards).
|
||||||
|
parentShardPollIntervalMillis = 10000
|
||||||
|
|
||||||
|
# Cleanup leases upon shards completion (don't wait until they expire in Kinesis).
|
||||||
|
# Keeping leases takes some tracking/resources (e.g. they need to be renewed, assigned), so by default we try
|
||||||
|
# to delete the ones we don't need any longer.
|
||||||
|
cleanupLeasesUponShardCompletion = true
|
||||||
|
|
||||||
|
# Backoff time in milliseconds for Amazon Kinesis Client Library tasks (in the event of failures).
|
||||||
|
taskBackoffTimeMillis = 500
|
||||||
|
|
||||||
|
# Buffer metrics for at most this long before publishing to CloudWatch.
|
||||||
|
metricsBufferTimeMillis = 10000
|
||||||
|
|
||||||
|
# Buffer at most this many metrics before publishing to CloudWatch.
|
||||||
|
metricsMaxQueueSize = 10000
|
||||||
|
|
||||||
|
# KCL will validate client provided sequence numbers with a call to Amazon Kinesis before checkpointing for calls
|
||||||
|
# to RecordProcessorCheckpointer#checkpoint(String) by default.
|
||||||
|
validateSequenceNumberBeforeCheckpointing = true
|
||||||
|
|
||||||
|
# The maximum number of active threads for the MultiLangDaemon to permit.
|
||||||
|
# If a value is provided then a FixedThreadPool is used with the maximum
|
||||||
|
# active threads set to the provided value. If a non-positive integer or no
|
||||||
|
# value is provided a CachedThreadPool is used.
|
||||||
|
maxActiveThreads = -1
|
||||||
|
|
||||||
|
################### KclV3 configurations ###################
|
||||||
|
# Coordinator config
|
||||||
|
clientVersionConfig = CLIENT_VERSION_CONFIG_3x
|
||||||
|
|
||||||
|
## Let all other config be defaults
|
||||||
|
## TODO: include table deletion protection and pitr config once its added
|
||||||
|
## Configurations to control how the CoordinatorState DDB table is created
|
||||||
|
## Default name is applicationName-CoordinatorState in PAY_PER_REQUEST
|
||||||
|
#coordinatorStateTableName = MultiLangTest-CoordinatorState-CustomName
|
||||||
|
#coordinatorStateBillingMode = PROVISIONED
|
||||||
|
#coordinatorStateReadCapacity = 1000
|
||||||
|
#coordinatorStateWriteCapacity = 500
|
||||||
|
#
|
||||||
|
## Graceful handoff config - tuning of the shutdown behavior during lease transfers
|
||||||
|
## default values are 30000 and true respectively
|
||||||
|
#gracefulLeaseHandoffTimeoutMillis = 10000
|
||||||
|
#isGracefulLeaseHandoffEnabled = false
|
||||||
|
#
|
||||||
|
## WorkerMetricStats table config - control how the DDB table is created
|
||||||
|
### Default name is applicationName-WorkerMetricStats in PAY_PER_REQUEST
|
||||||
|
## TODO: include table deletion protection and pitr config once its added
|
||||||
|
#workerMetricsTableName = MultiLangTest-WorkerMetrics-CustomName
|
||||||
|
#workerMetricsBillingMode = PROVISIONED
|
||||||
|
#workerMetricsReadCapacity = 250
|
||||||
|
#workerMetricsWriteCapacity = 90
|
||||||
|
#
|
||||||
|
## WorkerUtilizationAwareAssignment config - tune the new KCLv3 Lease balancing algorithm
|
||||||
|
##
|
||||||
|
## frequency of capturing worker metrics in memory. Default is 1s
|
||||||
|
#inMemoryWorkerMetricsCaptureFrequencyMillis = 5000
|
||||||
|
## frequency of reporting worker metric stats to storage. Default is 30s
|
||||||
|
#workerMetricsReporterFreqInMillis = 60000
|
||||||
|
## No. of metricStats that are persisted in WorkerMetricStats ddb table, default is 10.
|
||||||
|
## This provides historic values that are used to compute the workers current
|
||||||
|
## utilization using an exponential-moving-average.
|
||||||
|
#noOfPersistedMetricsPerWorkerMetrics = 50
|
||||||
|
## Disable use of worker metrics to balance lease, default is false.
|
||||||
|
## If it is true, the algorithm balances lease based on worker's processing throughput.
|
||||||
|
#disableWorkerMetrics = true
|
||||||
|
## Max throughput per host 10 MBps, to limit processing to the given value
|
||||||
|
## Default is unlimited.
|
||||||
|
#maxThroughputPerHostKBps = 10000
|
||||||
|
## Dampen the load that is rebalanced during lease re-balancing, default is 60%
|
||||||
|
#dampeningPercentage = 90
|
||||||
|
## Configures the allowed variance range for worker utilization. The upper
|
||||||
|
## limit is calculated as average * (1 + reBalanceThresholdPercentage/100).
|
||||||
|
## The lower limit is average * (1 - reBalanceThresholdPercentage/100). If
|
||||||
|
## any worker's utilization falls outside this range, lease re-balancing is
|
||||||
|
## triggered. The re-balancing algorithm aims to bring variance within the
|
||||||
|
## specified range. It also avoids thrashing by ensuring the utilization of
|
||||||
|
## the worker receiving the load after re-balancing doesn't exceed the fleet
|
||||||
|
## average. This might cause no re-balancing action even the utilization is
|
||||||
|
## out of the variance range. The default value is 10, representing +/-10%
|
||||||
|
## variance from the average value.
|
||||||
|
#reBalanceThresholdPercentage = 5
|
||||||
|
## Whether at-least one lease must be taken from a high utilization worker
|
||||||
|
## during re-balancing when there is no lease assigned to that worker which has
|
||||||
|
## throughput is less than or equal to the minimum throughput that needs to be
|
||||||
|
## moved away from that worker to bring the worker back into the allowed variance.
|
||||||
|
## Default is true.
|
||||||
|
#allowThroughputOvershoot = false
|
||||||
|
## Lease assignment is performed every failoverTimeMillis but re-balance will
|
||||||
|
## be attempted only once in 5 times based on the below config. Default is 3.
|
||||||
|
#varianceBalancingFrequency = 5
|
||||||
|
## Alpha value used for calculating exponential moving average of worker's metricStats.
|
||||||
|
## Default is 0.5, a higher alpha value will make re-balancing more sensitive
|
||||||
|
## to recent metricStats.
|
||||||
|
#workerMetricsEMAAlpha = 0.18
|
||||||
|
## Duration after which workerMetricStats entry from WorkerMetricStats table will
|
||||||
|
## be cleaned up. Default is 1 day.
|
||||||
|
## Duration format examples: PT15M (15 mins) PT10H (10 hours) P2D (2 days)
|
||||||
|
## Refer to Duration.parse javadocs for more details
|
||||||
|
#staleWorkerMetricsEntryCleanupDuration = PT12H
|
||||||
|
|
@ -123,7 +123,7 @@ public class CoordinatorConfig {
|
||||||
* This version also allows rolling back to the compatible mode from the
|
* This version also allows rolling back to the compatible mode from the
|
||||||
* auto-toggled 3.x mode.
|
* auto-toggled 3.x mode.
|
||||||
*/
|
*/
|
||||||
CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2x,
|
CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X,
|
||||||
/**
|
/**
|
||||||
* A new application operating with KCLv3.x will use this value. Also, an application
|
* A new application operating with KCLv3.x will use this value. Also, an application
|
||||||
* that has successfully upgraded to 3.x version and no longer needs the ability
|
* that has successfully upgraded to 3.x version and no longer needs the ability
|
||||||
|
|
@ -131,14 +131,14 @@ public class CoordinatorConfig {
|
||||||
* KCL will operate with new algorithms introduced in 3.x which is not compatible
|
* KCL will operate with new algorithms introduced in 3.x which is not compatible
|
||||||
* with prior versions. And once in this version, rollback to 2.x is not supported.
|
* with prior versions. And once in this version, rollback to 2.x is not supported.
|
||||||
*/
|
*/
|
||||||
CLIENT_VERSION_CONFIG_3x,
|
CLIENT_VERSION_CONFIG_3X,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client version KCL must operate in, by default it operates in 3.x version which is not
|
* Client version KCL must operate in, by default it operates in 3.x version which is not
|
||||||
* compatible with prior versions.
|
* compatible with prior versions.
|
||||||
*/
|
*/
|
||||||
private ClientVersionConfig clientVersionConfig = ClientVersionConfig.CLIENT_VERSION_CONFIG_3x;
|
private ClientVersionConfig clientVersionConfig = ClientVersionConfig.CLIENT_VERSION_CONFIG_3X;
|
||||||
|
|
||||||
public static class CoordinatorStateTableConfig extends DdbTableConfig {
|
public static class CoordinatorStateTableConfig extends DdbTableConfig {
|
||||||
private CoordinatorStateTableConfig(final String applicationName) {
|
private CoordinatorStateTableConfig(final String applicationName) {
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ public final class DynamicMigrationComponentsInitializer {
|
||||||
// always collect metrics so that when we flip to start reporting we will have accurate historical data.
|
// always collect metrics so that when we flip to start reporting we will have accurate historical data.
|
||||||
log.info("Start collection of WorkerMetricStats");
|
log.info("Start collection of WorkerMetricStats");
|
||||||
workerMetricsManager.startManager();
|
workerMetricsManager.startManager();
|
||||||
if (migrationStateMachineStartingClientVersion == ClientVersion.CLIENT_VERSION_3x) {
|
if (migrationStateMachineStartingClientVersion == ClientVersion.CLIENT_VERSION_3X) {
|
||||||
initializeComponentsFor3x();
|
initializeComponentsFor3x();
|
||||||
} else {
|
} else {
|
||||||
initializeComponentsForMigration(migrationStateMachineStartingClientVersion);
|
initializeComponentsForMigration(migrationStateMachineStartingClientVersion);
|
||||||
|
|
@ -187,7 +187,7 @@ public final class DynamicMigrationComponentsInitializer {
|
||||||
log.info("Initializing for migration to 3x");
|
log.info("Initializing for migration to 3x");
|
||||||
dualMode = true;
|
dualMode = true;
|
||||||
final LeaderDecider initialLeaderDecider;
|
final LeaderDecider initialLeaderDecider;
|
||||||
if (migrationStateMachineStartingClientVersion == ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK) {
|
if (migrationStateMachineStartingClientVersion == ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK) {
|
||||||
currentAssignmentMode = WORKER_UTILIZATION_AWARE_ASSIGNMENT;
|
currentAssignmentMode = WORKER_UTILIZATION_AWARE_ASSIGNMENT;
|
||||||
initialLeaderDecider = ddbLockBasedLeaderDeciderCreator.get();
|
initialLeaderDecider = ddbLockBasedLeaderDeciderCreator.get();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -292,8 +292,8 @@ public final class DynamicMigrationComponentsInitializer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize KCL with components and configuration to support upgrade from 2x. This can happen
|
* Initialize KCL with components and configuration to support upgrade from 2x. This can happen
|
||||||
* at KCL Worker startup when MigrationStateMachine starts in ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x.
|
* at KCL Worker startup when MigrationStateMachine starts in ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X.
|
||||||
* Or Dynamically during roll-forward from ClientVersion.CLIENT_VERSION_2x.
|
* Or Dynamically during roll-forward from ClientVersion.CLIENT_VERSION_2X.
|
||||||
*/
|
*/
|
||||||
public synchronized void initializeClientVersionForUpgradeFrom2x(final ClientVersion fromClientVersion)
|
public synchronized void initializeClientVersionForUpgradeFrom2x(final ClientVersion fromClientVersion)
|
||||||
throws DependencyException {
|
throws DependencyException {
|
||||||
|
|
@ -306,8 +306,8 @@ public final class DynamicMigrationComponentsInitializer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize KCL with components and configuration to run vanilla 3x functionality. This can happen
|
* Initialize KCL with components and configuration to run vanilla 3x functionality. This can happen
|
||||||
* at KCL Worker startup when MigrationStateMachine starts in ClientVersion.CLIENT_VERSION_3x, or dynamically
|
* at KCL Worker startup when MigrationStateMachine starts in ClientVersion.CLIENT_VERSION_3X, or dynamically
|
||||||
* during a new deployment when existing worker are in ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK
|
* during a new deployment when existing worker are in ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK
|
||||||
*/
|
*/
|
||||||
public synchronized void initializeClientVersionFor3x(final ClientVersion fromClientVersion)
|
public synchronized void initializeClientVersionFor3x(final ClientVersion fromClientVersion)
|
||||||
throws DependencyException {
|
throws DependencyException {
|
||||||
|
|
@ -322,14 +322,14 @@ public final class DynamicMigrationComponentsInitializer {
|
||||||
log.info("Starting LAM");
|
log.info("Starting LAM");
|
||||||
leaseAssignmentManager.start();
|
leaseAssignmentManager.start();
|
||||||
}
|
}
|
||||||
// nothing to do when transitioning from CLIENT_VERSION_3x_WITH_ROLLBACK.
|
// nothing to do when transitioning from CLIENT_VERSION_3X_WITH_ROLLBACK.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize KCL with components and configuration to run 2x compatible functionality
|
* Initialize KCL with components and configuration to run 2x compatible functionality
|
||||||
* while allowing roll-forward. This can happen at KCL Worker startup when MigrationStateMachine
|
* while allowing roll-forward. This can happen at KCL Worker startup when MigrationStateMachine
|
||||||
* starts in ClientVersion.CLIENT_VERSION_2x (after a rollback)
|
* starts in ClientVersion.CLIENT_VERSION_2X (after a rollback)
|
||||||
* Or Dynamically during rollback from CLIENT_VERSION_UPGRADE_FROM_2x or CLIENT_VERSION_3x_WITH_ROLLBACK.
|
* Or Dynamically during rollback from CLIENT_VERSION_UPGRADE_FROM_2X or CLIENT_VERSION_3X_WITH_ROLLBACK.
|
||||||
*/
|
*/
|
||||||
public synchronized void initializeClientVersionFor2x(final ClientVersion fromClientVersion) {
|
public synchronized void initializeClientVersionFor2x(final ClientVersion fromClientVersion) {
|
||||||
log.info("Initializing KCL components for rollback to 2x from {}", fromClientVersion);
|
log.info("Initializing KCL components for rollback to 2x from {}", fromClientVersion);
|
||||||
|
|
@ -341,7 +341,7 @@ public final class DynamicMigrationComponentsInitializer {
|
||||||
// and WorkerMetricStats table
|
// and WorkerMetricStats table
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fromClientVersion == ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK) {
|
if (fromClientVersion == ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK) {
|
||||||
// we are rolling back after flip
|
// we are rolling back after flip
|
||||||
currentAssignmentMode = DEFAULT_LEASE_COUNT_BASED_ASSIGNMENT;
|
currentAssignmentMode = DEFAULT_LEASE_COUNT_BASED_ASSIGNMENT;
|
||||||
notifyLeaseAssignmentModeChange();
|
notifyLeaseAssignmentModeChange();
|
||||||
|
|
@ -361,14 +361,14 @@ public final class DynamicMigrationComponentsInitializer {
|
||||||
/**
|
/**
|
||||||
* Initialize KCL with components and configuration to run vanilla 3x functionality
|
* Initialize KCL with components and configuration to run vanilla 3x functionality
|
||||||
* while allowing roll-back to 2x functionality. This can happen at KCL Worker startup
|
* while allowing roll-back to 2x functionality. This can happen at KCL Worker startup
|
||||||
* when MigrationStateMachine starts in ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK (after the flip)
|
* when MigrationStateMachine starts in ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK (after the flip)
|
||||||
* Or Dynamically during flip from CLIENT_VERSION_UPGRADE_FROM_2x.
|
* Or Dynamically during flip from CLIENT_VERSION_UPGRADE_FROM_2X.
|
||||||
*/
|
*/
|
||||||
public synchronized void initializeClientVersionFor3xWithRollback(final ClientVersion fromClientVersion)
|
public synchronized void initializeClientVersionFor3xWithRollback(final ClientVersion fromClientVersion)
|
||||||
throws DependencyException {
|
throws DependencyException {
|
||||||
log.info("Initializing KCL components for 3x with rollback from {}", fromClientVersion);
|
log.info("Initializing KCL components for 3x with rollback from {}", fromClientVersion);
|
||||||
|
|
||||||
if (fromClientVersion == ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x) {
|
if (fromClientVersion == ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X) {
|
||||||
// dynamic flip
|
// dynamic flip
|
||||||
currentAssignmentMode = WORKER_UTILIZATION_AWARE_ASSIGNMENT;
|
currentAssignmentMode = WORKER_UTILIZATION_AWARE_ASSIGNMENT;
|
||||||
notifyLeaseAssignmentModeChange();
|
notifyLeaseAssignmentModeChange();
|
||||||
|
|
|
||||||
|
|
@ -31,28 +31,28 @@ public enum ClientVersion {
|
||||||
* KCL workers will emit WorkerMetricStats and run KCLv2.x algorithms for leader election and lease
|
* KCL workers will emit WorkerMetricStats and run KCLv2.x algorithms for leader election and lease
|
||||||
* assignment. KCL will also monitor for upgrade to KCLv3.x readiness of the worker fleet.
|
* assignment. KCL will also monitor for upgrade to KCLv3.x readiness of the worker fleet.
|
||||||
*/
|
*/
|
||||||
CLIENT_VERSION_UPGRADE_FROM_2x,
|
CLIENT_VERSION_UPGRADE_FROM_2X,
|
||||||
/**
|
/**
|
||||||
* This version is used during rollback from CLIENT_VERSION_UPGRADE_FROM_2x or CLIENT_VERSION_3x_WITH_ROLLBACK,
|
* This version is used during rollback from CLIENT_VERSION_UPGRADE_FROM_2X or CLIENT_VERSION_3X_WITH_ROLLBACK,
|
||||||
* which can only be initiated using a KCL migration tool, when customer wants to revert to KCLv2.x functionality.
|
* which can only be initiated using a KCL migration tool, when customer wants to revert to KCLv2.x functionality.
|
||||||
* In this version, KCL will not emit WorkerMetricStats and run KCLv2.x algorithms for leader election
|
* In this version, KCL will not emit WorkerMetricStats and run KCLv2.x algorithms for leader election
|
||||||
* and lease assignment. In this version, KCL will monitor for roll-forward scenario where
|
* and lease assignment. In this version, KCL will monitor for roll-forward scenario where
|
||||||
* client version is updated to CLIENT_VERSION_UPGRADE_FROM_2x using the migration tool.
|
* client version is updated to CLIENT_VERSION_UPGRADE_FROM_2X using the migration tool.
|
||||||
*/
|
*/
|
||||||
CLIENT_VERSION_2x,
|
CLIENT_VERSION_2X,
|
||||||
/**
|
/**
|
||||||
* When workers are operating in CLIENT_VERSION_UPGRADE_FROM_2x and when worker fleet is determined to be
|
* When workers are operating in CLIENT_VERSION_UPGRADE_FROM_2X and when worker fleet is determined to be
|
||||||
* KCLv3.x ready (when lease table GSI is active and worker-metrics are being emitted by all lease owners)
|
* KCLv3.x ready (when lease table GSI is active and worker-metrics are being emitted by all lease owners)
|
||||||
* then the leader will initiate the switch to KCLv3.x algorithms for leader election and lease assignment,
|
* then the leader will initiate the switch to KCLv3.x algorithms for leader election and lease assignment,
|
||||||
* by using this version and persisting it in the {@link MigrationState} that allows all worker hosts
|
* by using this version and persisting it in the {@link MigrationState} that allows all worker hosts
|
||||||
* to also flip to KCLv3.x functionality. In this KCL will also monitor for rollback to detect when the
|
* to also flip to KCLv3.x functionality. In this KCL will also monitor for rollback to detect when the
|
||||||
* customer updates version to CLIENT_VERSION_2x using migration tool, so that it instantly flips back
|
* customer updates version to CLIENT_VERSION_2X using migration tool, so that it instantly flips back
|
||||||
* to CLIENT_VERSION_2x.
|
* to CLIENT_VERSION_2X.
|
||||||
*/
|
*/
|
||||||
CLIENT_VERSION_3x_WITH_ROLLBACK,
|
CLIENT_VERSION_3X_WITH_ROLLBACK,
|
||||||
/**
|
/**
|
||||||
* A new application starting KCLv3.x or an upgraded application from KCLv2.x after upgrade is successful
|
* A new application starting KCLv3.x or an upgraded application from KCLv2.x after upgrade is successful
|
||||||
* can use this version to default all KCLv3.x algorithms without any monitor to rollback.
|
* can use this version to default all KCLv3.x algorithms without any monitor to rollback.
|
||||||
*/
|
*/
|
||||||
CLIENT_VERSION_3x;
|
CLIENT_VERSION_3X;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -144,11 +144,11 @@ public class ClientVersionChangeMonitor implements Runnable {
|
||||||
final MetricsScope scope = MetricsUtil.createMetricsWithOperation(metricsFactory, METRICS_OPERATION);
|
final MetricsScope scope = MetricsUtil.createMetricsWithOperation(metricsFactory, METRICS_OPERATION);
|
||||||
try {
|
try {
|
||||||
switch (expectedVersion) {
|
switch (expectedVersion) {
|
||||||
case CLIENT_VERSION_3x_WITH_ROLLBACK:
|
case CLIENT_VERSION_3X_WITH_ROLLBACK:
|
||||||
scope.addData("CurrentState:3xWorker", 1, StandardUnit.COUNT, MetricsLevel.SUMMARY);
|
scope.addData("CurrentState:3xWorker", 1, StandardUnit.COUNT, MetricsLevel.SUMMARY);
|
||||||
break;
|
break;
|
||||||
case CLIENT_VERSION_2x:
|
case CLIENT_VERSION_2X:
|
||||||
case CLIENT_VERSION_UPGRADE_FROM_2x:
|
case CLIENT_VERSION_UPGRADE_FROM_2X:
|
||||||
scope.addData("CurrentState:2xCompatibleWorker", 1, StandardUnit.COUNT, MetricsLevel.SUMMARY);
|
scope.addData("CurrentState:2xCompatibleWorker", 1, StandardUnit.COUNT, MetricsLevel.SUMMARY);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,13 @@ import software.amazon.kinesis.metrics.MetricsLevel;
|
||||||
import software.amazon.kinesis.metrics.MetricsScope;
|
import software.amazon.kinesis.metrics.MetricsScope;
|
||||||
import software.amazon.kinesis.metrics.MetricsUtil;
|
import software.amazon.kinesis.metrics.MetricsUtil;
|
||||||
|
|
||||||
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_2x;
|
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_2X;
|
||||||
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x;
|
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X;
|
||||||
import static software.amazon.kinesis.coordinator.migration.MigrationStateMachineImpl.FAULT_METRIC;
|
import static software.amazon.kinesis.coordinator.migration.MigrationStateMachineImpl.FAULT_METRIC;
|
||||||
import static software.amazon.kinesis.coordinator.migration.MigrationStateMachineImpl.METRICS_OPERATION;
|
import static software.amazon.kinesis.coordinator.migration.MigrationStateMachineImpl.METRICS_OPERATION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* State for CLIENT_VERSION_2x. In this state, the only allowed valid transition is
|
* State for CLIENT_VERSION_2X. In this state, the only allowed valid transition is
|
||||||
* the roll-forward scenario which can only be performed using the KCL Migration tool.
|
* the roll-forward scenario which can only be performed using the KCL Migration tool.
|
||||||
* So when the state machine enters this state, a monitor is started to detect the
|
* So when the state machine enters this state, a monitor is started to detect the
|
||||||
* roll-forward scenario.
|
* roll-forward scenario.
|
||||||
|
|
@ -60,7 +60,7 @@ public class MigrationClientVersion2xState implements MigrationClientVersionStat
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientVersion clientVersion() {
|
public ClientVersion clientVersion() {
|
||||||
return CLIENT_VERSION_2x;
|
return CLIENT_VERSION_2X;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -102,7 +102,7 @@ public class MigrationClientVersion2xState implements MigrationClientVersionStat
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback handler to handle client version changes in MigrationState in DDB.
|
* Callback handler to handle client version changes in MigrationState in DDB.
|
||||||
* @param newState current MigrationState read from DDB where client version is not CLIENT_VERSION_2x
|
* @param newState current MigrationState read from DDB where client version is not CLIENT_VERSION_2X
|
||||||
* @throws InvalidStateException during transition to the next state based on the new ClientVersion
|
* @throws InvalidStateException during transition to the next state based on the new ClientVersion
|
||||||
* or if the new state in DDB is unexpected.
|
* or if the new state in DDB is unexpected.
|
||||||
*/
|
*/
|
||||||
|
|
@ -115,18 +115,18 @@ public class MigrationClientVersion2xState implements MigrationClientVersionStat
|
||||||
final MetricsScope scope =
|
final MetricsScope scope =
|
||||||
MetricsUtil.createMetricsWithOperation(initializer.metricsFactory(), METRICS_OPERATION);
|
MetricsUtil.createMetricsWithOperation(initializer.metricsFactory(), METRICS_OPERATION);
|
||||||
try {
|
try {
|
||||||
if (newState.getClientVersion() == CLIENT_VERSION_UPGRADE_FROM_2x) {
|
if (newState.getClientVersion() == CLIENT_VERSION_UPGRADE_FROM_2X) {
|
||||||
log.info(
|
log.info(
|
||||||
"A roll-forward has been initiated for the application. Transition to {}",
|
"A roll-forward has been initiated for the application. Transition to {}",
|
||||||
CLIENT_VERSION_UPGRADE_FROM_2x);
|
CLIENT_VERSION_UPGRADE_FROM_2X);
|
||||||
// If this succeeds, the monitor will cancel itself.
|
// If this succeeds, the monitor will cancel itself.
|
||||||
stateMachine.transitionTo(CLIENT_VERSION_UPGRADE_FROM_2x, newState);
|
stateMachine.transitionTo(CLIENT_VERSION_UPGRADE_FROM_2X, newState);
|
||||||
} else {
|
} else {
|
||||||
// This should not happen, so throw an exception that allows the monitor to continue monitoring
|
// This should not happen, so throw an exception that allows the monitor to continue monitoring
|
||||||
// changes, this allows KCL to operate in the current state and keep monitoring until a valid
|
// changes, this allows KCL to operate in the current state and keep monitoring until a valid
|
||||||
// state transition is possible.
|
// state transition is possible.
|
||||||
// However, there could be a split brain here, new workers will use DDB value as source of truth,
|
// However, there could be a split brain here, new workers will use DDB value as source of truth,
|
||||||
// so we could also write back CLIENT_VERSION_2x to DDB to ensure all workers have consistent
|
// so we could also write back CLIENT_VERSION_2X to DDB to ensure all workers have consistent
|
||||||
// behavior.
|
// behavior.
|
||||||
// Ideally we don't expect modifications to DDB table out of the KCL migration tool scope,
|
// Ideally we don't expect modifications to DDB table out of the KCL migration tool scope,
|
||||||
// so keeping it simple and not writing back to DDB, the error log below would help capture
|
// so keeping it simple and not writing back to DDB, the error log below would help capture
|
||||||
|
|
@ -134,7 +134,7 @@ public class MigrationClientVersion2xState implements MigrationClientVersionStat
|
||||||
log.error(
|
log.error(
|
||||||
"Migration state has invalid client version {}. Transition from {} is not supported",
|
"Migration state has invalid client version {}. Transition from {} is not supported",
|
||||||
newState,
|
newState,
|
||||||
CLIENT_VERSION_2x);
|
CLIENT_VERSION_2X);
|
||||||
throw new InvalidStateException(String.format("Unexpected new state %s", newState));
|
throw new InvalidStateException(String.format("Unexpected new state %s", newState));
|
||||||
}
|
}
|
||||||
} catch (final InvalidStateException | DependencyException e) {
|
} catch (final InvalidStateException | DependencyException e) {
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import software.amazon.kinesis.coordinator.DynamicMigrationComponentsInitializer
|
||||||
import software.amazon.kinesis.leases.exceptions.DependencyException;
|
import software.amazon.kinesis.leases.exceptions.DependencyException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* State for CLIENT_VERSION_3x which enables KCL to run 3.x algorithms on new KCLv3.x application
|
* State for CLIENT_VERSION_3X which enables KCL to run 3.x algorithms on new KCLv3.x application
|
||||||
* or successfully upgraded application which upgraded from v2.x. This is a terminal state of the
|
* or successfully upgraded application which upgraded from v2.x. This is a terminal state of the
|
||||||
* state machine and no rollbacks are supported in this state.
|
* state machine and no rollbacks are supported in this state.
|
||||||
*/
|
*/
|
||||||
|
|
@ -38,7 +38,7 @@ public class MigrationClientVersion3xState implements MigrationClientVersionStat
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientVersion clientVersion() {
|
public ClientVersion clientVersion() {
|
||||||
return ClientVersion.CLIENT_VERSION_3x;
|
return ClientVersion.CLIENT_VERSION_3X;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -31,15 +31,15 @@ import software.amazon.kinesis.metrics.MetricsLevel;
|
||||||
import software.amazon.kinesis.metrics.MetricsScope;
|
import software.amazon.kinesis.metrics.MetricsScope;
|
||||||
import software.amazon.kinesis.metrics.MetricsUtil;
|
import software.amazon.kinesis.metrics.MetricsUtil;
|
||||||
|
|
||||||
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_2x;
|
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_2X;
|
||||||
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_3x;
|
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_3X;
|
||||||
import static software.amazon.kinesis.coordinator.migration.MigrationStateMachineImpl.FAULT_METRIC;
|
import static software.amazon.kinesis.coordinator.migration.MigrationStateMachineImpl.FAULT_METRIC;
|
||||||
import static software.amazon.kinesis.coordinator.migration.MigrationStateMachineImpl.METRICS_OPERATION;
|
import static software.amazon.kinesis.coordinator.migration.MigrationStateMachineImpl.METRICS_OPERATION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* State for CLIENT_VERSION_3x_WITH_ROLLBACK which enables KCL to run its 3.x compliant algorithms
|
* State for CLIENT_VERSION_3X_WITH_ROLLBACK which enables KCL to run its 3.x compliant algorithms
|
||||||
* during the upgrade process after all KCL workers in the fleet are 3.x complaint. Since this
|
* during the upgrade process after all KCL workers in the fleet are 3.x complaint. Since this
|
||||||
* is an instant switch from CLIENT_VERSION_UPGRADE_FROM_2x, it also supports rollback if customers
|
* is an instant switch from CLIENT_VERSION_UPGRADE_FROM_2X, it also supports rollback if customers
|
||||||
* see regression to allow for instant rollbacks as well. This would be achieved by customers
|
* see regression to allow for instant rollbacks as well. This would be achieved by customers
|
||||||
* running a KCL migration tool to update MigrationState in DDB. So this state monitors for
|
* running a KCL migration tool to update MigrationState in DDB. So this state monitors for
|
||||||
* rollback triggers and performs state transitions accordingly.
|
* rollback triggers and performs state transitions accordingly.
|
||||||
|
|
@ -62,7 +62,7 @@ public class MigrationClientVersion3xWithRollbackState implements MigrationClien
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientVersion clientVersion() {
|
public ClientVersion clientVersion() {
|
||||||
return ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK;
|
return ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -108,17 +108,17 @@ public class MigrationClientVersion3xWithRollbackState implements MigrationClien
|
||||||
MetricsUtil.createMetricsWithOperation(initializer.metricsFactory(), METRICS_OPERATION);
|
MetricsUtil.createMetricsWithOperation(initializer.metricsFactory(), METRICS_OPERATION);
|
||||||
try {
|
try {
|
||||||
switch (newState.getClientVersion()) {
|
switch (newState.getClientVersion()) {
|
||||||
case CLIENT_VERSION_2x:
|
case CLIENT_VERSION_2X:
|
||||||
log.info("A rollback has been initiated for the application. Transition to {}", CLIENT_VERSION_2x);
|
log.info("A rollback has been initiated for the application. Transition to {}", CLIENT_VERSION_2X);
|
||||||
stateMachine.transitionTo(ClientVersion.CLIENT_VERSION_2x, newState);
|
stateMachine.transitionTo(ClientVersion.CLIENT_VERSION_2X, newState);
|
||||||
break;
|
break;
|
||||||
case CLIENT_VERSION_3x:
|
case CLIENT_VERSION_3X:
|
||||||
log.info("Customer has switched to 3.x after successful upgrade, state machine will move to a"
|
log.info("Customer has switched to 3.x after successful upgrade, state machine will move to a"
|
||||||
+ "terminal state and stop monitoring. Rollbacks will no longer be supported anymore");
|
+ "terminal state and stop monitoring. Rollbacks will no longer be supported anymore");
|
||||||
stateMachine.transitionTo(CLIENT_VERSION_3x, newState);
|
stateMachine.transitionTo(CLIENT_VERSION_3X, newState);
|
||||||
// This worker will still be running the migrationAdaptive components in 3.x mode which will
|
// This worker will still be running the migrationAdaptive components in 3.x mode which will
|
||||||
// no longer dynamically switch back to 2.x mode, however to directly run 3.x component without
|
// no longer dynamically switch back to 2.x mode, however to directly run 3.x component without
|
||||||
// adaption to migration (i.e. move to CLIENT_VERSION_3x state), it requires this worker to go
|
// adaption to migration (i.e. move to CLIENT_VERSION_3X state), it requires this worker to go
|
||||||
// through the current deployment which initiated the switch to 3.x mode.
|
// through the current deployment which initiated the switch to 3.x mode.
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -126,7 +126,7 @@ public class MigrationClientVersion3xWithRollbackState implements MigrationClien
|
||||||
// changes, this allows KCL to operate in the current state and keep monitoring until a valid
|
// changes, this allows KCL to operate in the current state and keep monitoring until a valid
|
||||||
// state transition is possible.
|
// state transition is possible.
|
||||||
// However, there could be a split brain here, new workers will use DDB value as source of truth,
|
// However, there could be a split brain here, new workers will use DDB value as source of truth,
|
||||||
// so we could also write back CLIENT_VERSION_3x_WITH_ROLLBACK to DDB to ensure all workers have
|
// so we could also write back CLIENT_VERSION_3X_WITH_ROLLBACK to DDB to ensure all workers have
|
||||||
// consistent behavior.
|
// consistent behavior.
|
||||||
// Ideally we don't expect modifications to DDB table out of the KCL migration tool scope,
|
// Ideally we don't expect modifications to DDB table out of the KCL migration tool scope,
|
||||||
// so keeping it simple and not writing back to DDB, the error log below would help capture
|
// so keeping it simple and not writing back to DDB, the error log below would help capture
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,10 @@ import software.amazon.kinesis.leases.exceptions.DependencyException;
|
||||||
import software.amazon.kinesis.leases.exceptions.InvalidStateException;
|
import software.amazon.kinesis.leases.exceptions.InvalidStateException;
|
||||||
import software.amazon.kinesis.leases.exceptions.ProvisionedThroughputException;
|
import software.amazon.kinesis.leases.exceptions.ProvisionedThroughputException;
|
||||||
|
|
||||||
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_2x;
|
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_2X;
|
||||||
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_3x;
|
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_3X;
|
||||||
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK;
|
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK;
|
||||||
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x;
|
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X;
|
||||||
import static software.amazon.kinesis.coordinator.migration.MigrationState.MIGRATION_HASH_KEY;
|
import static software.amazon.kinesis.coordinator.migration.MigrationState.MIGRATION_HASH_KEY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -44,13 +44,13 @@ import static software.amazon.kinesis.coordinator.migration.MigrationState.MIGRA
|
||||||
* as follows
|
* as follows
|
||||||
* ClientVersionConfig | MigrationState (DDB) | initial client version
|
* ClientVersionConfig | MigrationState (DDB) | initial client version
|
||||||
* --------------------+---------------------------------+--------------------------------
|
* --------------------+---------------------------------+--------------------------------
|
||||||
* COMPATIBLE_WITH_2x | Does not exist | CLIENT_VERSION_UPGRADE_FROM_2x
|
* COMPATIBLE_WITH_2X | Does not exist | CLIENT_VERSION_UPGRADE_FROM_2X
|
||||||
* 3x | Does not exist | CLIENT_VERSION_3x
|
* 3X | Does not exist | CLIENT_VERSION_3X
|
||||||
* COMPATIBLE_WITH_2x | CLIENT_VERSION_3x_WITH_ROLLBACK | CLIENT_VERSION_3x_WITH_ROLLBACK
|
* COMPATIBLE_WITH_2X | CLIENT_VERSION_3X_WITH_ROLLBACK | CLIENT_VERSION_3X_WITH_ROLLBACK
|
||||||
* 3x | CLIENT_VERSION_3x_WITH_ROLLBACK | CLIENT_VERSION_3x
|
* 3X | CLIENT_VERSION_3X_WITH_ROLLBACK | CLIENT_VERSION_3X
|
||||||
* any | CLIENT_VERSION_2x | CLIENT_VERSION_2x
|
* any | CLIENT_VERSION_2X | CLIENT_VERSION_2X
|
||||||
* any | CLIENT_VERSION_UPGRADE_FROM_2x | CLIENT_VERSION_UPGRADE_FROM_2x
|
* any | CLIENT_VERSION_UPGRADE_FROM_2X | CLIENT_VERSION_UPGRADE_FROM_2X
|
||||||
* any | CLIENT_VERSION_3x | CLIENT_VERSION_3x
|
* any | CLIENT_VERSION_3X | CLIENT_VERSION_3X
|
||||||
*/
|
*/
|
||||||
@KinesisClientInternalApi
|
@KinesisClientInternalApi
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
|
@ -110,26 +110,26 @@ public class MigrationClientVersionStateInitializer {
|
||||||
nextClientVersion = getNextClientVersionBasedOnConfigVersion();
|
nextClientVersion = getNextClientVersionBasedOnConfigVersion();
|
||||||
log.info("Application is starting in {}", nextClientVersion);
|
log.info("Application is starting in {}", nextClientVersion);
|
||||||
break;
|
break;
|
||||||
case CLIENT_VERSION_3x_WITH_ROLLBACK:
|
case CLIENT_VERSION_3X_WITH_ROLLBACK:
|
||||||
if (clientVersionConfig == ClientVersionConfig.CLIENT_VERSION_CONFIG_3x) {
|
if (clientVersionConfig == ClientVersionConfig.CLIENT_VERSION_CONFIG_3X) {
|
||||||
// upgrade successful, allow transition to 3x.
|
// upgrade successful, allow transition to 3x.
|
||||||
log.info("Application has successfully upgraded, transitioning to {}", CLIENT_VERSION_3x);
|
log.info("Application has successfully upgraded, transitioning to {}", CLIENT_VERSION_3X);
|
||||||
nextClientVersion = CLIENT_VERSION_3x;
|
nextClientVersion = CLIENT_VERSION_3X;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
log.info("Initialize with {}", CLIENT_VERSION_3x_WITH_ROLLBACK);
|
log.info("Initialize with {}", CLIENT_VERSION_3X_WITH_ROLLBACK);
|
||||||
nextClientVersion = migrationState.getClientVersion();
|
nextClientVersion = migrationState.getClientVersion();
|
||||||
break;
|
break;
|
||||||
case CLIENT_VERSION_2x:
|
case CLIENT_VERSION_2X:
|
||||||
log.info("Application has rolled-back, initialize with {}", CLIENT_VERSION_2x);
|
log.info("Application has rolled-back, initialize with {}", CLIENT_VERSION_2X);
|
||||||
nextClientVersion = migrationState.getClientVersion();
|
nextClientVersion = migrationState.getClientVersion();
|
||||||
break;
|
break;
|
||||||
case CLIENT_VERSION_UPGRADE_FROM_2x:
|
case CLIENT_VERSION_UPGRADE_FROM_2X:
|
||||||
log.info("Application is upgrading, initialize with {}", CLIENT_VERSION_UPGRADE_FROM_2x);
|
log.info("Application is upgrading, initialize with {}", CLIENT_VERSION_UPGRADE_FROM_2X);
|
||||||
nextClientVersion = migrationState.getClientVersion();
|
nextClientVersion = migrationState.getClientVersion();
|
||||||
break;
|
break;
|
||||||
case CLIENT_VERSION_3x:
|
case CLIENT_VERSION_3X:
|
||||||
log.info("Initialize with {}", CLIENT_VERSION_3x);
|
log.info("Initialize with {}", CLIENT_VERSION_3X);
|
||||||
nextClientVersion = migrationState.getClientVersion();
|
nextClientVersion = migrationState.getClientVersion();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -180,10 +180,10 @@ public class MigrationClientVersionStateInitializer {
|
||||||
|
|
||||||
private ClientVersion getNextClientVersionBasedOnConfigVersion() {
|
private ClientVersion getNextClientVersionBasedOnConfigVersion() {
|
||||||
switch (clientVersionConfig) {
|
switch (clientVersionConfig) {
|
||||||
case CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2x:
|
case CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X:
|
||||||
return CLIENT_VERSION_UPGRADE_FROM_2x;
|
return CLIENT_VERSION_UPGRADE_FROM_2X;
|
||||||
case CLIENT_VERSION_CONFIG_3x:
|
case CLIENT_VERSION_CONFIG_3X:
|
||||||
return CLIENT_VERSION_3x;
|
return CLIENT_VERSION_3X;
|
||||||
}
|
}
|
||||||
throw new IllegalStateException(String.format("Unknown configured Client version %s", clientVersionConfig));
|
throw new IllegalStateException(String.format("Unknown configured Client version %s", clientVersionConfig));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,23 +32,23 @@ import software.amazon.kinesis.metrics.MetricsLevel;
|
||||||
import software.amazon.kinesis.metrics.MetricsScope;
|
import software.amazon.kinesis.metrics.MetricsScope;
|
||||||
import software.amazon.kinesis.metrics.MetricsUtil;
|
import software.amazon.kinesis.metrics.MetricsUtil;
|
||||||
|
|
||||||
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_2x;
|
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_2X;
|
||||||
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK;
|
import static software.amazon.kinesis.coordinator.migration.ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK;
|
||||||
import static software.amazon.kinesis.coordinator.migration.MigrationStateMachineImpl.FAULT_METRIC;
|
import static software.amazon.kinesis.coordinator.migration.MigrationStateMachineImpl.FAULT_METRIC;
|
||||||
import static software.amazon.kinesis.coordinator.migration.MigrationStateMachineImpl.METRICS_OPERATION;
|
import static software.amazon.kinesis.coordinator.migration.MigrationStateMachineImpl.METRICS_OPERATION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* State for CLIENT_VERSION_UPGRADE_FROM_2x. When state machine enters this state,
|
* State for CLIENT_VERSION_UPGRADE_FROM_2X. When state machine enters this state,
|
||||||
* KCL is initialized to operate in dual mode for Lease assignment and Leader decider algorithms
|
* KCL is initialized to operate in dual mode for Lease assignment and Leader decider algorithms
|
||||||
* which initially start in 2.x compatible mode and when all the KCL workers are 3.x compliant,
|
* which initially start in 2.x compatible mode and when all the KCL workers are 3.x compliant,
|
||||||
* it dynamically switches to the 3.x algorithms. It also monitors for rollback
|
* it dynamically switches to the 3.x algorithms. It also monitors for rollback
|
||||||
* initiated from customer via the KCL migration tool and instantly switches back to the 2.x
|
* initiated from customer via the KCL migration tool and instantly switches back to the 2.x
|
||||||
* complaint algorithms.
|
* complaint algorithms.
|
||||||
* The allowed state transitions are to CLIENT_VERSION_3x_WITH_ROLLBACK when KCL workers are
|
* The allowed state transitions are to CLIENT_VERSION_3X_WITH_ROLLBACK when KCL workers are
|
||||||
* 3.x complaint, and to CLIENT_VERSION_2x when customer has initiated a rollback.
|
* 3.x complaint, and to CLIENT_VERSION_2X when customer has initiated a rollback.
|
||||||
* Only the leader KCL worker performs migration ready monitor and notifies all workers (including
|
* Only the leader KCL worker performs migration ready monitor and notifies all workers (including
|
||||||
* itself) via a MigrationState update. When all worker's monitor notice the MigrationState change
|
* itself) via a MigrationState update. When all worker's monitor notice the MigrationState change
|
||||||
* (including itself), it will transition to CLIENT_VERSION_3x_WITH_ROLLBACK.
|
* (including itself), it will transition to CLIENT_VERSION_3X_WITH_ROLLBACK.
|
||||||
*/
|
*/
|
||||||
@KinesisClientInternalApi
|
@KinesisClientInternalApi
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
|
@ -71,7 +71,7 @@ public class MigrationClientVersionUpgradeFrom2xState implements MigrationClient
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientVersion clientVersion() {
|
public ClientVersion clientVersion() {
|
||||||
return ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x;
|
return ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -170,7 +170,7 @@ public class MigrationClientVersionUpgradeFrom2xState implements MigrationClient
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback handler to handle client version changes in MigrationState in DDB.
|
* Callback handler to handle client version changes in MigrationState in DDB.
|
||||||
* @param newState current MigrationState read from DDB where client version is not CLIENT_VERSION_UPGRADE_FROM_2x
|
* @param newState current MigrationState read from DDB where client version is not CLIENT_VERSION_UPGRADE_FROM_2X
|
||||||
* @throws InvalidStateException during transition to the next state based on the new ClientVersion
|
* @throws InvalidStateException during transition to the next state based on the new ClientVersion
|
||||||
* or if the new state in DDB is unexpected.
|
* or if the new state in DDB is unexpected.
|
||||||
*/
|
*/
|
||||||
|
|
@ -184,23 +184,23 @@ public class MigrationClientVersionUpgradeFrom2xState implements MigrationClient
|
||||||
MetricsUtil.createMetricsWithOperation(initializer.metricsFactory(), METRICS_OPERATION);
|
MetricsUtil.createMetricsWithOperation(initializer.metricsFactory(), METRICS_OPERATION);
|
||||||
try {
|
try {
|
||||||
switch (newState.getClientVersion()) {
|
switch (newState.getClientVersion()) {
|
||||||
case CLIENT_VERSION_2x:
|
case CLIENT_VERSION_2X:
|
||||||
log.info("A rollback has been initiated for the application. Transition to {}", CLIENT_VERSION_2x);
|
log.info("A rollback has been initiated for the application. Transition to {}", CLIENT_VERSION_2X);
|
||||||
// cancel monitor asynchronously
|
// cancel monitor asynchronously
|
||||||
cancelMigrationReadyMonitor();
|
cancelMigrationReadyMonitor();
|
||||||
stateMachine.transitionTo(CLIENT_VERSION_2x, newState);
|
stateMachine.transitionTo(CLIENT_VERSION_2X, newState);
|
||||||
break;
|
break;
|
||||||
case CLIENT_VERSION_3x_WITH_ROLLBACK:
|
case CLIENT_VERSION_3X_WITH_ROLLBACK:
|
||||||
log.info("KCL workers are v3.x compliant, transition to {}", CLIENT_VERSION_3x_WITH_ROLLBACK);
|
log.info("KCL workers are v3.x compliant, transition to {}", CLIENT_VERSION_3X_WITH_ROLLBACK);
|
||||||
cancelMigrationReadyMonitor();
|
cancelMigrationReadyMonitor();
|
||||||
stateMachine.transitionTo(CLIENT_VERSION_3x_WITH_ROLLBACK, newState);
|
stateMachine.transitionTo(CLIENT_VERSION_3X_WITH_ROLLBACK, newState);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// This should not happen, so throw an exception that allows the monitor to continue monitoring
|
// This should not happen, so throw an exception that allows the monitor to continue monitoring
|
||||||
// changes, this allows KCL to operate in the current state and keep monitoring until a valid
|
// changes, this allows KCL to operate in the current state and keep monitoring until a valid
|
||||||
// state transition is possible.
|
// state transition is possible.
|
||||||
// However, there could be a split brain here, new workers will use DDB value as source of truth,
|
// However, there could be a split brain here, new workers will use DDB value as source of truth,
|
||||||
// so we could also write back CLIENT_VERSION_UPGRADE_FROM_2x to DDB to ensure all workers have
|
// so we could also write back CLIENT_VERSION_UPGRADE_FROM_2X to DDB to ensure all workers have
|
||||||
// consistent behavior.
|
// consistent behavior.
|
||||||
// Ideally we don't expect modifications to DDB table out of the KCL migration tool scope,
|
// Ideally we don't expect modifications to DDB table out of the KCL migration tool scope,
|
||||||
// so keeping it simple and not writing back to DDB, the error log below would help capture
|
// so keeping it simple and not writing back to DDB, the error log below would help capture
|
||||||
|
|
@ -222,7 +222,7 @@ public class MigrationClientVersionUpgradeFrom2xState implements MigrationClient
|
||||||
try {
|
try {
|
||||||
final MigrationState newMigrationState = currentMigrationState
|
final MigrationState newMigrationState = currentMigrationState
|
||||||
.copy()
|
.copy()
|
||||||
.update(CLIENT_VERSION_3x_WITH_ROLLBACK, initializer.workerIdentifier());
|
.update(CLIENT_VERSION_3X_WITH_ROLLBACK, initializer.workerIdentifier());
|
||||||
log.info("Updating Migration State in DDB with {} prev state {}", newMigrationState, currentMigrationState);
|
log.info("Updating Migration State in DDB with {} prev state {}", newMigrationState, currentMigrationState);
|
||||||
return coordinatorStateDAO.updateCoordinatorStateWithExpectation(
|
return coordinatorStateDAO.updateCoordinatorStateWithExpectation(
|
||||||
newMigrationState, currentMigrationState.getDynamoClientVersionExpectation());
|
newMigrationState, currentMigrationState.getDynamoClientVersionExpectation());
|
||||||
|
|
@ -230,7 +230,7 @@ public class MigrationClientVersionUpgradeFrom2xState implements MigrationClient
|
||||||
log.warn(
|
log.warn(
|
||||||
"Exception occurred when toggling to {}, upgradeReadyMonitor will retry the update"
|
"Exception occurred when toggling to {}, upgradeReadyMonitor will retry the update"
|
||||||
+ " if upgrade condition is still true",
|
+ " if upgrade condition is still true",
|
||||||
CLIENT_VERSION_3x_WITH_ROLLBACK,
|
CLIENT_VERSION_3X_WITH_ROLLBACK,
|
||||||
e);
|
e);
|
||||||
scope.addData(FAULT_METRIC, 1, StandardUnit.COUNT, MetricsLevel.SUMMARY);
|
scope.addData(FAULT_METRIC, 1, StandardUnit.COUNT, MetricsLevel.SUMMARY);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ public class MigrationStateMachineImpl implements MigrationStateMachine {
|
||||||
|
|
||||||
currentMigrationClientVersionState = nextMigrationClientVersionState;
|
currentMigrationClientVersionState = nextMigrationClientVersionState;
|
||||||
log.info("Successfully transitioned to {}", nextMigrationClientVersionState.clientVersion());
|
log.info("Successfully transitioned to {}", nextMigrationClientVersionState.clientVersion());
|
||||||
if (currentMigrationClientVersionState.clientVersion() == ClientVersion.CLIENT_VERSION_3x) {
|
if (currentMigrationClientVersionState.clientVersion() == ClientVersion.CLIENT_VERSION_3X) {
|
||||||
terminate();
|
terminate();
|
||||||
}
|
}
|
||||||
success = true;
|
success = true;
|
||||||
|
|
@ -220,10 +220,10 @@ public class MigrationStateMachineImpl implements MigrationStateMachine {
|
||||||
private MigrationClientVersionState createMigrationClientVersionState(
|
private MigrationClientVersionState createMigrationClientVersionState(
|
||||||
final ClientVersion clientVersion, final MigrationState migrationState) {
|
final ClientVersion clientVersion, final MigrationState migrationState) {
|
||||||
switch (clientVersion) {
|
switch (clientVersion) {
|
||||||
case CLIENT_VERSION_2x:
|
case CLIENT_VERSION_2X:
|
||||||
return new MigrationClientVersion2xState(
|
return new MigrationClientVersion2xState(
|
||||||
this, coordinatorStateDAO, stateMachineThreadPool, initializer, random);
|
this, coordinatorStateDAO, stateMachineThreadPool, initializer, random);
|
||||||
case CLIENT_VERSION_UPGRADE_FROM_2x:
|
case CLIENT_VERSION_UPGRADE_FROM_2X:
|
||||||
return new MigrationClientVersionUpgradeFrom2xState(
|
return new MigrationClientVersionUpgradeFrom2xState(
|
||||||
this,
|
this,
|
||||||
timeProvider,
|
timeProvider,
|
||||||
|
|
@ -233,10 +233,10 @@ public class MigrationStateMachineImpl implements MigrationStateMachine {
|
||||||
random,
|
random,
|
||||||
migrationState,
|
migrationState,
|
||||||
flipTo3XStabilizerTimeInSeconds);
|
flipTo3XStabilizerTimeInSeconds);
|
||||||
case CLIENT_VERSION_3x_WITH_ROLLBACK:
|
case CLIENT_VERSION_3X_WITH_ROLLBACK:
|
||||||
return new MigrationClientVersion3xWithRollbackState(
|
return new MigrationClientVersion3xWithRollbackState(
|
||||||
this, coordinatorStateDAO, stateMachineThreadPool, initializer, random);
|
this, coordinatorStateDAO, stateMachineThreadPool, initializer, random);
|
||||||
case CLIENT_VERSION_3x:
|
case CLIENT_VERSION_3X:
|
||||||
return new MigrationClientVersion3xState(this, initializer);
|
return new MigrationClientVersion3xState(this, initializer);
|
||||||
}
|
}
|
||||||
throw new IllegalStateException(String.format("Unknown client version %s", clientVersion));
|
throw new IllegalStateException(String.format("Unknown client version %s", clientVersion));
|
||||||
|
|
@ -246,7 +246,7 @@ public class MigrationStateMachineImpl implements MigrationStateMachine {
|
||||||
if (currentMigrationClientVersionState != null) {
|
if (currentMigrationClientVersionState != null) {
|
||||||
return currentMigrationClientVersionState.clientVersion();
|
return currentMigrationClientVersionState.clientVersion();
|
||||||
} else if (terminated) {
|
} else if (terminated) {
|
||||||
return ClientVersion.CLIENT_VERSION_3x;
|
return ClientVersion.CLIENT_VERSION_3X;
|
||||||
}
|
}
|
||||||
throw new UnsupportedOperationException(
|
throw new UnsupportedOperationException(
|
||||||
"No current state when state machine is either not initialized" + " or already terminated");
|
"No current state when state machine is either not initialized" + " or already terminated");
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ import java.util.function.Function;
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
@ -381,8 +380,8 @@ public class LeaseManagementConfig {
|
||||||
* to shut down and an option to enable or disable graceful lease handoff.
|
* to shut down and an option to enable or disable graceful lease handoff.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@Getter
|
|
||||||
@Accessors(fluent = true)
|
@Accessors(fluent = true)
|
||||||
public static class GracefulLeaseHandoffConfig {
|
public static class GracefulLeaseHandoffConfig {
|
||||||
/**
|
/**
|
||||||
|
|
@ -550,7 +549,7 @@ public class LeaseManagementConfig {
|
||||||
private int dampeningPercentage = 60;
|
private int dampeningPercentage = 60;
|
||||||
/**
|
/**
|
||||||
* Percentage value used to trigger reBalance. If fleet has workers which are have metrics value more or less
|
* Percentage value used to trigger reBalance. If fleet has workers which are have metrics value more or less
|
||||||
* than 20% of fleet level average then reBalance is triggered.
|
* than 10% of fleet level average then reBalance is triggered.
|
||||||
* Leases are taken from workers with metrics value more than fleet level average. The load to take from these
|
* Leases are taken from workers with metrics value more than fleet level average. The load to take from these
|
||||||
* workers is determined by evaluating how far they are with respect to fleet level average.
|
* workers is determined by evaluating how far they are with respect to fleet level average.
|
||||||
*/
|
*/
|
||||||
|
|
@ -565,7 +564,7 @@ public class LeaseManagementConfig {
|
||||||
private boolean allowThroughputOvershoot = true;
|
private boolean allowThroughputOvershoot = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Duration after which workerMetrics entry from WorkerMetricStats table will be cleaned up. When an entry's
|
* Duration after which workerMetricStats entry from WorkerMetricStats table will be cleaned up. When an entry's
|
||||||
* lastUpdateTime is older than staleWorkerMetricsEntryCleanupDuration from current time, entry will be removed
|
* lastUpdateTime is older than staleWorkerMetricsEntryCleanupDuration from current time, entry will be removed
|
||||||
* from the table.
|
* from the table.
|
||||||
*/
|
*/
|
||||||
|
|
@ -580,15 +579,16 @@ public class LeaseManagementConfig {
|
||||||
private WorkerMetricsTableConfig workerMetricsTableConfig;
|
private WorkerMetricsTableConfig workerMetricsTableConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frequency to perform worker variance balancing frequency. This value is used with respect to the LAM freq,
|
* Frequency to perform worker variance balancing. This value is used with respect to the LAM frequency,
|
||||||
* that is every third (as default) iteration of LAM the worker variance balancing will be performed.
|
* that is every third (as default) iteration of LAM the worker variance balancing will be performed.
|
||||||
* Setting it to 1 will make varianceBalancing run on every iteration of LAM and 2 on every 2nd iteration
|
* Setting it to 1 will make varianceBalancing run on every iteration of LAM and 2 on every 2nd iteration
|
||||||
* and so on.
|
* and so on.
|
||||||
|
* NOTE: LAM frequency = failoverTimeMillis
|
||||||
*/
|
*/
|
||||||
private int varianceBalancingFrequency = 3;
|
private int varianceBalancingFrequency = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alpha value used for calculating exponential moving average of worker's metrics values. Selecting
|
* Alpha value used for calculating exponential moving average of worker's metricStats. Selecting
|
||||||
* higher alpha value gives more weightage to recent value and thus low smoothing effect on computed average
|
* higher alpha value gives more weightage to recent value and thus low smoothing effect on computed average
|
||||||
* and selecting smaller alpha values gives more weightage to past value and high smoothing effect.
|
* and selecting smaller alpha values gives more weightage to past value and high smoothing effect.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ public class CoordinatorStateDAOTest {
|
||||||
createCoordinatorState("key1");
|
createCoordinatorState("key1");
|
||||||
|
|
||||||
final MigrationState migrationState = new MigrationState(MIGRATION_HASH_KEY, WORKER_ID)
|
final MigrationState migrationState = new MigrationState(MIGRATION_HASH_KEY, WORKER_ID)
|
||||||
.update(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x, WORKER_ID);
|
.update(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X, WORKER_ID);
|
||||||
doaUnderTest.createCoordinatorStateIfNotExists(migrationState);
|
doaUnderTest.createCoordinatorStateIfNotExists(migrationState);
|
||||||
|
|
||||||
final AmazonDynamoDBLockClient dynamoDBLockClient = new AmazonDynamoDBLockClient(doaUnderTest
|
final AmazonDynamoDBLockClient dynamoDBLockClient = new AmazonDynamoDBLockClient(doaUnderTest
|
||||||
|
|
@ -223,7 +223,7 @@ public class CoordinatorStateDAOTest {
|
||||||
// Make sure the record has not changed due to using
|
// Make sure the record has not changed due to using
|
||||||
// ddb lock client
|
// ddb lock client
|
||||||
Assertions.assertEquals(
|
Assertions.assertEquals(
|
||||||
ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x.toString(),
|
ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X.toString(),
|
||||||
item.get(CLIENT_VERSION_ATTRIBUTE_NAME).s());
|
item.get(CLIENT_VERSION_ATTRIBUTE_NAME).s());
|
||||||
} else if (LEADER_HASH_KEY.equals(key)) {
|
} else if (LEADER_HASH_KEY.equals(key)) {
|
||||||
Assertions.assertEquals("TEST_WORKER", item.get("ownerName").s());
|
Assertions.assertEquals("TEST_WORKER", item.get("ownerName").s());
|
||||||
|
|
@ -264,7 +264,7 @@ public class CoordinatorStateDAOTest {
|
||||||
if ("Migration3.0".equals(keyValue)) {
|
if ("Migration3.0".equals(keyValue)) {
|
||||||
Assertions.assertTrue(state instanceof MigrationState);
|
Assertions.assertTrue(state instanceof MigrationState);
|
||||||
final MigrationState migrationState = (MigrationState) state;
|
final MigrationState migrationState = (MigrationState) state;
|
||||||
Assertions.assertEquals(ClientVersion.CLIENT_VERSION_3x, migrationState.getClientVersion());
|
Assertions.assertEquals(ClientVersion.CLIENT_VERSION_3X, migrationState.getClientVersion());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Assertions.assertEquals(3, state.getAttributes().size());
|
Assertions.assertEquals(3, state.getAttributes().size());
|
||||||
|
|
@ -379,7 +379,7 @@ public class CoordinatorStateDAOTest {
|
||||||
final MigrationState state = createMigrationState();
|
final MigrationState state = createMigrationState();
|
||||||
|
|
||||||
/* Test step - update the state with mismatched condition */
|
/* Test step - update the state with mismatched condition */
|
||||||
final MigrationState updatedState = state.copy().update(ClientVersion.CLIENT_VERSION_2x, WORKER_ID);
|
final MigrationState updatedState = state.copy().update(ClientVersion.CLIENT_VERSION_2X, WORKER_ID);
|
||||||
|
|
||||||
boolean updated = doaUnderTest.updateCoordinatorStateWithExpectation(
|
boolean updated = doaUnderTest.updateCoordinatorStateWithExpectation(
|
||||||
updatedState, updatedState.getDynamoClientVersionExpectation());
|
updatedState, updatedState.getDynamoClientVersionExpectation());
|
||||||
|
|
@ -403,7 +403,7 @@ public class CoordinatorStateDAOTest {
|
||||||
.build())
|
.build())
|
||||||
.join();
|
.join();
|
||||||
Assertions.assertEquals(
|
Assertions.assertEquals(
|
||||||
ClientVersion.CLIENT_VERSION_2x.name(),
|
ClientVersion.CLIENT_VERSION_2X.name(),
|
||||||
response.item().get("cv").s());
|
response.item().get("cv").s());
|
||||||
Assertions.assertEquals(WORKER_ID, response.item().get("mb").s());
|
Assertions.assertEquals(WORKER_ID, response.item().get("mb").s());
|
||||||
Assertions.assertEquals(
|
Assertions.assertEquals(
|
||||||
|
|
@ -433,7 +433,7 @@ public class CoordinatorStateDAOTest {
|
||||||
|
|
||||||
/* Test step - update with new state object */
|
/* Test step - update with new state object */
|
||||||
final MigrationState updatedState =
|
final MigrationState updatedState =
|
||||||
new MigrationState("Migration3.0", WORKER_ID).update(ClientVersion.CLIENT_VERSION_2x, WORKER_ID);
|
new MigrationState("Migration3.0", WORKER_ID).update(ClientVersion.CLIENT_VERSION_2X, WORKER_ID);
|
||||||
|
|
||||||
boolean updated = doaUnderTest.updateCoordinatorStateWithExpectation(updatedState, null);
|
boolean updated = doaUnderTest.updateCoordinatorStateWithExpectation(updatedState, null);
|
||||||
|
|
||||||
|
|
@ -491,7 +491,7 @@ public class CoordinatorStateDAOTest {
|
||||||
final HashMap<String, AttributeValue> item = new HashMap<String, AttributeValue>() {
|
final HashMap<String, AttributeValue> item = new HashMap<String, AttributeValue>() {
|
||||||
{
|
{
|
||||||
put("key", AttributeValue.fromS("Migration3.0"));
|
put("key", AttributeValue.fromS("Migration3.0"));
|
||||||
put("cv", AttributeValue.fromS(ClientVersion.CLIENT_VERSION_3x.toString()));
|
put("cv", AttributeValue.fromS(ClientVersion.CLIENT_VERSION_3X.toString()));
|
||||||
put("mb", AttributeValue.fromS("DUMMY_WORKER"));
|
put("mb", AttributeValue.fromS("DUMMY_WORKER"));
|
||||||
put("mts", AttributeValue.fromN(String.valueOf(System.currentTimeMillis())));
|
put("mts", AttributeValue.fromN(String.valueOf(System.currentTimeMillis())));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ public class DynamicMigrationComponentsInitializerTest {
|
||||||
@Test
|
@Test
|
||||||
public void testInitialize_ClientVersion3_X() throws DependencyException {
|
public void testInitialize_ClientVersion3_X() throws DependencyException {
|
||||||
// Test initializing to verify correct leader decider is created
|
// Test initializing to verify correct leader decider is created
|
||||||
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_3x);
|
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_3X);
|
||||||
|
|
||||||
verify(mockWorkerMetricsManager).startManager();
|
verify(mockWorkerMetricsManager).startManager();
|
||||||
verify(mockDdbLockBasedLeaderDeciderCreator).get();
|
verify(mockDdbLockBasedLeaderDeciderCreator).get();
|
||||||
|
|
@ -147,7 +147,7 @@ public class DynamicMigrationComponentsInitializerTest {
|
||||||
@Test
|
@Test
|
||||||
public void testInitialize_ClientVersion_3_xWithRollback() throws DependencyException {
|
public void testInitialize_ClientVersion_3_xWithRollback() throws DependencyException {
|
||||||
// Test initializing to verify correct leader decider is created
|
// Test initializing to verify correct leader decider is created
|
||||||
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK);
|
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK);
|
||||||
|
|
||||||
verify(mockWorkerMetricsManager).startManager();
|
verify(mockWorkerMetricsManager).startManager();
|
||||||
|
|
||||||
|
|
@ -171,7 +171,7 @@ public class DynamicMigrationComponentsInitializerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@CsvSource({"CLIENT_VERSION_UPGRADE_FROM_2x", "CLIENT_VERSION_2x"})
|
@CsvSource({"CLIENT_VERSION_UPGRADE_FROM_2X", "CLIENT_VERSION_2X"})
|
||||||
public void testInitialize_ClientVersion_All2_X(final ClientVersion clientVersion) throws DependencyException {
|
public void testInitialize_ClientVersion_All2_X(final ClientVersion clientVersion) throws DependencyException {
|
||||||
// Test initializing to verify correct leader decider is created
|
// Test initializing to verify correct leader decider is created
|
||||||
migrationInitializer.initialize(clientVersion);
|
migrationInitializer.initialize(clientVersion);
|
||||||
|
|
@ -187,7 +187,7 @@ public class DynamicMigrationComponentsInitializerTest {
|
||||||
verify(mockConsumer).initialize(eq(true), eq(LeaseAssignmentMode.DEFAULT_LEASE_COUNT_BASED_ASSIGNMENT));
|
verify(mockConsumer).initialize(eq(true), eq(LeaseAssignmentMode.DEFAULT_LEASE_COUNT_BASED_ASSIGNMENT));
|
||||||
|
|
||||||
// test initialization from state machine
|
// test initialization from state machine
|
||||||
if (clientVersion == ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x) {
|
if (clientVersion == ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X) {
|
||||||
migrationInitializer.initializeClientVersionForUpgradeFrom2x(ClientVersion.CLIENT_VERSION_INIT);
|
migrationInitializer.initializeClientVersionForUpgradeFrom2x(ClientVersion.CLIENT_VERSION_INIT);
|
||||||
// start worker stats and create gsi without waiting
|
// start worker stats and create gsi without waiting
|
||||||
verify(mockWorkerMetricsDAO).initialize();
|
verify(mockWorkerMetricsDAO).initialize();
|
||||||
|
|
@ -211,7 +211,7 @@ public class DynamicMigrationComponentsInitializerTest {
|
||||||
when(mockLamThreadPool.awaitTermination(anyLong(), any())).thenReturn(true);
|
when(mockLamThreadPool.awaitTermination(anyLong(), any())).thenReturn(true);
|
||||||
when(mockWorkerMetricsScheduler.awaitTermination(anyLong(), any())).thenReturn(true);
|
when(mockWorkerMetricsScheduler.awaitTermination(anyLong(), any())).thenReturn(true);
|
||||||
|
|
||||||
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x);
|
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X);
|
||||||
migrationInitializer.shutdown();
|
migrationInitializer.shutdown();
|
||||||
|
|
||||||
verify(mockLamThreadPool).shutdown();
|
verify(mockLamThreadPool).shutdown();
|
||||||
|
|
@ -226,7 +226,7 @@ public class DynamicMigrationComponentsInitializerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void initializationFails_WhenGsiIsNotActiveIn3_X() throws DependencyException {
|
public void initializationFails_WhenGsiIsNotActiveIn3_X() throws DependencyException {
|
||||||
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_3x);
|
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_3X);
|
||||||
// test initialization from state machine
|
// test initialization from state machine
|
||||||
|
|
||||||
assertThrows(
|
assertThrows(
|
||||||
|
|
@ -236,7 +236,7 @@ public class DynamicMigrationComponentsInitializerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void initializationDoesNotFail_WhenGsiIsNotActiveIn3_XWithRollback() throws DependencyException {
|
public void initializationDoesNotFail_WhenGsiIsNotActiveIn3_XWithRollback() throws DependencyException {
|
||||||
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK);
|
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK);
|
||||||
// test initialization from state machine
|
// test initialization from state machine
|
||||||
|
|
||||||
assertDoesNotThrow(
|
assertDoesNotThrow(
|
||||||
|
|
@ -245,11 +245,11 @@ public class DynamicMigrationComponentsInitializerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComponentsInitialization_AfterFlip() throws DependencyException {
|
public void testComponentsInitialization_AfterFlip() throws DependencyException {
|
||||||
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x);
|
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X);
|
||||||
migrationInitializer.initializeClientVersionForUpgradeFrom2x(ClientVersion.CLIENT_VERSION_INIT);
|
migrationInitializer.initializeClientVersionForUpgradeFrom2x(ClientVersion.CLIENT_VERSION_INIT);
|
||||||
|
|
||||||
// Test flip
|
// Test flip
|
||||||
migrationInitializer.initializeClientVersionFor3xWithRollback(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x);
|
migrationInitializer.initializeClientVersionFor3xWithRollback(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X);
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
verify(mockLam).start();
|
verify(mockLam).start();
|
||||||
|
|
@ -266,13 +266,13 @@ public class DynamicMigrationComponentsInitializerTest {
|
||||||
.when(mockWorkerMetricsScheduler)
|
.when(mockWorkerMetricsScheduler)
|
||||||
.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class));
|
.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class));
|
||||||
|
|
||||||
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_2x);
|
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_2X);
|
||||||
migrationInitializer.initializeClientVersionFor2x(ClientVersion.CLIENT_VERSION_INIT);
|
migrationInitializer.initializeClientVersionFor2x(ClientVersion.CLIENT_VERSION_INIT);
|
||||||
|
|
||||||
// test roll-forward
|
// test roll-forward
|
||||||
reset(mockWorkerMetricsScheduler);
|
reset(mockWorkerMetricsScheduler);
|
||||||
reset(mockLeaseRefresher);
|
reset(mockLeaseRefresher);
|
||||||
migrationInitializer.initializeClientVersionForUpgradeFrom2x(ClientVersion.CLIENT_VERSION_2x);
|
migrationInitializer.initializeClientVersionForUpgradeFrom2x(ClientVersion.CLIENT_VERSION_2X);
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
verify(mockWorkerMetricsScheduler)
|
verify(mockWorkerMetricsScheduler)
|
||||||
|
|
@ -288,11 +288,11 @@ public class DynamicMigrationComponentsInitializerTest {
|
||||||
.when(mockWorkerMetricsScheduler)
|
.when(mockWorkerMetricsScheduler)
|
||||||
.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class));
|
.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class));
|
||||||
|
|
||||||
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x);
|
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X);
|
||||||
migrationInitializer.initializeClientVersionForUpgradeFrom2x(ClientVersion.CLIENT_VERSION_INIT);
|
migrationInitializer.initializeClientVersionForUpgradeFrom2x(ClientVersion.CLIENT_VERSION_INIT);
|
||||||
|
|
||||||
// test rollback before flip
|
// test rollback before flip
|
||||||
migrationInitializer.initializeClientVersionFor2x(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x);
|
migrationInitializer.initializeClientVersionFor2x(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X);
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
verify(mockFuture).cancel(anyBoolean());
|
verify(mockFuture).cancel(anyBoolean());
|
||||||
|
|
@ -305,11 +305,11 @@ public class DynamicMigrationComponentsInitializerTest {
|
||||||
.when(mockWorkerMetricsScheduler)
|
.when(mockWorkerMetricsScheduler)
|
||||||
.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class));
|
.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class));
|
||||||
|
|
||||||
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK);
|
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK);
|
||||||
migrationInitializer.initializeClientVersionFor3xWithRollback(ClientVersion.CLIENT_VERSION_INIT);
|
migrationInitializer.initializeClientVersionFor3xWithRollback(ClientVersion.CLIENT_VERSION_INIT);
|
||||||
|
|
||||||
// test rollback before flip
|
// test rollback before flip
|
||||||
migrationInitializer.initializeClientVersionFor2x(ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK);
|
migrationInitializer.initializeClientVersionFor2x(ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK);
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
verify(mockFuture).cancel(anyBoolean());
|
verify(mockFuture).cancel(anyBoolean());
|
||||||
|
|
@ -337,7 +337,7 @@ public class DynamicMigrationComponentsInitializerTest {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK);
|
migrationInitializer.initialize(ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK);
|
||||||
migrationInitializer.initializeClientVersionFor3xWithRollback(ClientVersion.CLIENT_VERSION_INIT);
|
migrationInitializer.initializeClientVersionFor3xWithRollback(ClientVersion.CLIENT_VERSION_INIT);
|
||||||
|
|
||||||
// run the worker stats reporting thread
|
// run the worker stats reporting thread
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,10 @@ public class ClientVersionChangeMonitorTest {
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@CsvSource({
|
@CsvSource({
|
||||||
"CLIENT_VERSION_2x, CLIENT_VERSION_UPGRADE_FROM_2x",
|
"CLIENT_VERSION_2X, CLIENT_VERSION_UPGRADE_FROM_2X",
|
||||||
"CLIENT_VERSION_3x_WITH_ROLLBACK, CLIENT_VERSION_2x",
|
"CLIENT_VERSION_3X_WITH_ROLLBACK, CLIENT_VERSION_2X",
|
||||||
"CLIENT_VERSION_UPGRADE_FROM_2x, CLIENT_VERSION_3x_WITH_ROLLBACK",
|
"CLIENT_VERSION_UPGRADE_FROM_2X, CLIENT_VERSION_3X_WITH_ROLLBACK",
|
||||||
"CLIENT_VERSION_3x_WITH_ROLLBACK, CLIENT_VERSION_3x"
|
"CLIENT_VERSION_3X_WITH_ROLLBACK, CLIENT_VERSION_3X"
|
||||||
})
|
})
|
||||||
public void testMonitor(final ClientVersion currentClientVersion, final ClientVersion changedClientVersion)
|
public void testMonitor(final ClientVersion currentClientVersion, final ClientVersion changedClientVersion)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
@ -104,7 +104,7 @@ public class ClientVersionChangeMonitorTest {
|
||||||
mockCoordinatorStateDAO,
|
mockCoordinatorStateDAO,
|
||||||
mockScheduler,
|
mockScheduler,
|
||||||
mockCallback,
|
mockCallback,
|
||||||
ClientVersion.CLIENT_VERSION_2x,
|
ClientVersion.CLIENT_VERSION_2X,
|
||||||
mockRandom);
|
mockRandom);
|
||||||
|
|
||||||
monitorUnderTest.startMonitor();
|
monitorUnderTest.startMonitor();
|
||||||
|
|
@ -112,7 +112,7 @@ public class ClientVersionChangeMonitorTest {
|
||||||
verify(mockScheduler).scheduleWithFixedDelay(argumentCaptor.capture(), anyLong(), anyLong(), anyObject());
|
verify(mockScheduler).scheduleWithFixedDelay(argumentCaptor.capture(), anyLong(), anyLong(), anyObject());
|
||||||
|
|
||||||
final MigrationState state = new MigrationState(MIGRATION_HASH_KEY, "DUMMY_WORKER")
|
final MigrationState state = new MigrationState(MIGRATION_HASH_KEY, "DUMMY_WORKER")
|
||||||
.update(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x, "DUMMY_WORKER");
|
.update(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X, "DUMMY_WORKER");
|
||||||
when(mockCoordinatorStateDAO.getCoordinatorState(MIGRATION_HASH_KEY)).thenReturn(state);
|
when(mockCoordinatorStateDAO.getCoordinatorState(MIGRATION_HASH_KEY)).thenReturn(state);
|
||||||
|
|
||||||
argumentCaptor.getValue().run();
|
argumentCaptor.getValue().run();
|
||||||
|
|
@ -130,7 +130,7 @@ public class ClientVersionChangeMonitorTest {
|
||||||
mockCoordinatorStateDAO,
|
mockCoordinatorStateDAO,
|
||||||
mockScheduler,
|
mockScheduler,
|
||||||
mockCallback,
|
mockCallback,
|
||||||
ClientVersion.CLIENT_VERSION_2x,
|
ClientVersion.CLIENT_VERSION_2X,
|
||||||
mockRandom);
|
mockRandom);
|
||||||
|
|
||||||
monitorUnderTest.startMonitor();
|
monitorUnderTest.startMonitor();
|
||||||
|
|
@ -138,7 +138,7 @@ public class ClientVersionChangeMonitorTest {
|
||||||
verify(mockScheduler).scheduleWithFixedDelay(argumentCaptor.capture(), anyLong(), anyLong(), anyObject());
|
verify(mockScheduler).scheduleWithFixedDelay(argumentCaptor.capture(), anyLong(), anyLong(), anyObject());
|
||||||
|
|
||||||
final MigrationState state = new MigrationState(MIGRATION_HASH_KEY, "DUMMY_WORKER")
|
final MigrationState state = new MigrationState(MIGRATION_HASH_KEY, "DUMMY_WORKER")
|
||||||
.update(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x, "DUMMY_WORKER");
|
.update(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X, "DUMMY_WORKER");
|
||||||
when(mockCoordinatorStateDAO.getCoordinatorState(MIGRATION_HASH_KEY)).thenReturn(state);
|
when(mockCoordinatorStateDAO.getCoordinatorState(MIGRATION_HASH_KEY)).thenReturn(state);
|
||||||
|
|
||||||
doThrow(new InvalidStateException("test exception")).when(mockCallback).accept(any());
|
doThrow(new InvalidStateException("test exception")).when(mockCallback).accept(any());
|
||||||
|
|
|
||||||
|
|
@ -107,8 +107,8 @@ public class MigrationStateMachineTest {
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@CsvSource({
|
@CsvSource({
|
||||||
"CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2x, CLIENT_VERSION_UPGRADE_FROM_2x",
|
"CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X, CLIENT_VERSION_UPGRADE_FROM_2X",
|
||||||
"CLIENT_VERSION_CONFIG_3x, CLIENT_VERSION_3x"
|
"CLIENT_VERSION_CONFIG_3X, CLIENT_VERSION_3X"
|
||||||
})
|
})
|
||||||
public void testStateMachineInitialization(
|
public void testStateMachineInitialization(
|
||||||
final ClientVersionConfig config, final ClientVersion expectedStateMachineState) throws Exception {
|
final ClientVersionConfig config, final ClientVersion expectedStateMachineState) throws Exception {
|
||||||
|
|
@ -118,7 +118,7 @@ public class MigrationStateMachineTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMigrationReadyFlip() throws Exception {
|
public void testMigrationReadyFlip() throws Exception {
|
||||||
stateMachineUnderTest = getStateMachineUnderTest(ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2x);
|
stateMachineUnderTest = getStateMachineUnderTest(ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X);
|
||||||
|
|
||||||
// After initialization, state machine should start to monitor for upgrade readiness
|
// After initialization, state machine should start to monitor for upgrade readiness
|
||||||
final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
||||||
|
|
@ -130,7 +130,7 @@ public class MigrationStateMachineTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRollbackAfterFlip() throws Exception {
|
public void testRollbackAfterFlip() throws Exception {
|
||||||
stateMachineUnderTest = getStateMachineUnderTest(ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2x);
|
stateMachineUnderTest = getStateMachineUnderTest(ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X);
|
||||||
|
|
||||||
// After initialization, state machine should start to monitor for upgrade readiness
|
// After initialization, state machine should start to monitor for upgrade readiness
|
||||||
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
||||||
|
|
@ -150,7 +150,7 @@ public class MigrationStateMachineTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRollForward() throws Exception {
|
public void testRollForward() throws Exception {
|
||||||
stateMachineUnderTest = getStateMachineUnderTest(ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2x);
|
stateMachineUnderTest = getStateMachineUnderTest(ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X);
|
||||||
|
|
||||||
// After initialization, state machine should start to monitor for upgrade readiness
|
// After initialization, state machine should start to monitor for upgrade readiness
|
||||||
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
||||||
|
|
@ -177,7 +177,7 @@ public class MigrationStateMachineTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRollbackBeforeFlip() throws Exception {
|
public void testRollbackBeforeFlip() throws Exception {
|
||||||
stateMachineUnderTest = getStateMachineUnderTest(ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2x);
|
stateMachineUnderTest = getStateMachineUnderTest(ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X);
|
||||||
|
|
||||||
// After initialization, state machine should start to monitor for upgrade readiness
|
// After initialization, state machine should start to monitor for upgrade readiness
|
||||||
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
||||||
|
|
@ -189,7 +189,7 @@ public class MigrationStateMachineTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void successfulUpgradeAfterFlip() throws Exception {
|
public void successfulUpgradeAfterFlip() throws Exception {
|
||||||
stateMachineUnderTest = getStateMachineUnderTest(ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2x);
|
stateMachineUnderTest = getStateMachineUnderTest(ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X);
|
||||||
|
|
||||||
// After initialization, state machine should start to monitor for upgrade readiness
|
// After initialization, state machine should start to monitor for upgrade readiness
|
||||||
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
||||||
|
|
@ -244,15 +244,15 @@ public class MigrationStateMachineTest {
|
||||||
// Invoke the monitor callbacks so the version flips to 3.x with rollback
|
// Invoke the monitor callbacks so the version flips to 3.x with rollback
|
||||||
migrationReadyMonitorRunnable.run();
|
migrationReadyMonitorRunnable.run();
|
||||||
Assertions.assertEquals(
|
Assertions.assertEquals(
|
||||||
ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK,
|
ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK,
|
||||||
stateCaptor.getValue().getClientVersion());
|
stateCaptor.getValue().getClientVersion());
|
||||||
|
|
||||||
versionChangeMonitorRunnable.run();
|
versionChangeMonitorRunnable.run();
|
||||||
Assertions.assertEquals(
|
Assertions.assertEquals(
|
||||||
ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK, stateMachineUnderTest.getCurrentClientVersion());
|
ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK, stateMachineUnderTest.getCurrentClientVersion());
|
||||||
|
|
||||||
verify(mockInitializer)
|
verify(mockInitializer)
|
||||||
.initializeClientVersionFor3xWithRollback(eq(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x));
|
.initializeClientVersionFor3xWithRollback(eq(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X));
|
||||||
log.info("TestLog ----------- flip done -------------");
|
log.info("TestLog ----------- flip done -------------");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -263,33 +263,33 @@ public class MigrationStateMachineTest {
|
||||||
: runnableCaptor.getAllValues().get(1);
|
: runnableCaptor.getAllValues().get(1);
|
||||||
|
|
||||||
final MigrationState state =
|
final MigrationState state =
|
||||||
new MigrationState(MIGRATION_HASH_KEY, WORKER_ID).update(ClientVersion.CLIENT_VERSION_2x, WORKER_ID);
|
new MigrationState(MIGRATION_HASH_KEY, WORKER_ID).update(ClientVersion.CLIENT_VERSION_2X, WORKER_ID);
|
||||||
when(mockCoordinatorStateDAO.getCoordinatorState(MIGRATION_HASH_KEY)).thenReturn(state);
|
when(mockCoordinatorStateDAO.getCoordinatorState(MIGRATION_HASH_KEY)).thenReturn(state);
|
||||||
reset(mockMigrationStateMachineThreadPool);
|
reset(mockMigrationStateMachineThreadPool);
|
||||||
reset(mockInitializer);
|
reset(mockInitializer);
|
||||||
log.info("TestLog ----------- Initiate rollback before flip -------------");
|
log.info("TestLog ----------- Initiate rollback before flip -------------");
|
||||||
versionChangeMonitorRunnable.run();
|
versionChangeMonitorRunnable.run();
|
||||||
log.info("TestLog ----------- rollback before flip done -------------");
|
log.info("TestLog ----------- rollback before flip done -------------");
|
||||||
Assertions.assertEquals(ClientVersion.CLIENT_VERSION_2x, stateMachineUnderTest.getCurrentClientVersion());
|
Assertions.assertEquals(ClientVersion.CLIENT_VERSION_2X, stateMachineUnderTest.getCurrentClientVersion());
|
||||||
verify(mockInitializer).initializeClientVersionFor2x(eq(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x));
|
verify(mockInitializer).initializeClientVersionFor2x(eq(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initiateAndTestRollBack(final Runnable rollbackMonitorRunnable) throws Exception {
|
private void initiateAndTestRollBack(final Runnable rollbackMonitorRunnable) throws Exception {
|
||||||
final MigrationState state =
|
final MigrationState state =
|
||||||
new MigrationState(MIGRATION_HASH_KEY, WORKER_ID).update(ClientVersion.CLIENT_VERSION_2x, WORKER_ID);
|
new MigrationState(MIGRATION_HASH_KEY, WORKER_ID).update(ClientVersion.CLIENT_VERSION_2X, WORKER_ID);
|
||||||
when(mockCoordinatorStateDAO.getCoordinatorState(MIGRATION_HASH_KEY)).thenReturn(state);
|
when(mockCoordinatorStateDAO.getCoordinatorState(MIGRATION_HASH_KEY)).thenReturn(state);
|
||||||
reset(mockMigrationStateMachineThreadPool);
|
reset(mockMigrationStateMachineThreadPool);
|
||||||
reset(mockInitializer);
|
reset(mockInitializer);
|
||||||
log.info("TestLog ----------- Initiate rollback -------------");
|
log.info("TestLog ----------- Initiate rollback -------------");
|
||||||
rollbackMonitorRunnable.run();
|
rollbackMonitorRunnable.run();
|
||||||
log.info("TestLog ----------- rollback done -------------");
|
log.info("TestLog ----------- rollback done -------------");
|
||||||
Assertions.assertEquals(ClientVersion.CLIENT_VERSION_2x, stateMachineUnderTest.getCurrentClientVersion());
|
Assertions.assertEquals(ClientVersion.CLIENT_VERSION_2X, stateMachineUnderTest.getCurrentClientVersion());
|
||||||
verify(mockInitializer).initializeClientVersionFor2x(eq(ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK));
|
verify(mockInitializer).initializeClientVersionFor2x(eq(ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initiateAndTestRollForward(final Runnable rollforwardMonitorRunnable) throws Exception {
|
private void initiateAndTestRollForward(final Runnable rollforwardMonitorRunnable) throws Exception {
|
||||||
final MigrationState state = new MigrationState(MIGRATION_HASH_KEY, WORKER_ID)
|
final MigrationState state = new MigrationState(MIGRATION_HASH_KEY, WORKER_ID)
|
||||||
.update(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x, WORKER_ID);
|
.update(ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X, WORKER_ID);
|
||||||
when(mockCoordinatorStateDAO.getCoordinatorState(MIGRATION_HASH_KEY)).thenReturn(state);
|
when(mockCoordinatorStateDAO.getCoordinatorState(MIGRATION_HASH_KEY)).thenReturn(state);
|
||||||
reset(mockMigrationStateMachineThreadPool);
|
reset(mockMigrationStateMachineThreadPool);
|
||||||
reset(mockInitializer);
|
reset(mockInitializer);
|
||||||
|
|
@ -297,20 +297,20 @@ public class MigrationStateMachineTest {
|
||||||
rollforwardMonitorRunnable.run();
|
rollforwardMonitorRunnable.run();
|
||||||
log.info("TestLog ----------- roll-forward done -------------");
|
log.info("TestLog ----------- roll-forward done -------------");
|
||||||
Assertions.assertEquals(
|
Assertions.assertEquals(
|
||||||
ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2x, stateMachineUnderTest.getCurrentClientVersion());
|
ClientVersion.CLIENT_VERSION_UPGRADE_FROM_2X, stateMachineUnderTest.getCurrentClientVersion());
|
||||||
verify(mockInitializer).initializeClientVersionForUpgradeFrom2x(eq(ClientVersion.CLIENT_VERSION_2x));
|
verify(mockInitializer).initializeClientVersionForUpgradeFrom2x(eq(ClientVersion.CLIENT_VERSION_2X));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initiateAndTestSuccessfulUpgrade(final Runnable successfulUpgradeMonitor) throws Exception {
|
private void initiateAndTestSuccessfulUpgrade(final Runnable successfulUpgradeMonitor) throws Exception {
|
||||||
final MigrationState state =
|
final MigrationState state =
|
||||||
new MigrationState(MIGRATION_HASH_KEY, WORKER_ID).update(ClientVersion.CLIENT_VERSION_3x, WORKER_ID);
|
new MigrationState(MIGRATION_HASH_KEY, WORKER_ID).update(ClientVersion.CLIENT_VERSION_3X, WORKER_ID);
|
||||||
when(mockCoordinatorStateDAO.getCoordinatorState(MIGRATION_HASH_KEY)).thenReturn(state);
|
when(mockCoordinatorStateDAO.getCoordinatorState(MIGRATION_HASH_KEY)).thenReturn(state);
|
||||||
reset(mockMigrationStateMachineThreadPool);
|
reset(mockMigrationStateMachineThreadPool);
|
||||||
reset(mockInitializer);
|
reset(mockInitializer);
|
||||||
log.info("TestLog ----------- Initiate successful upgrade -------------");
|
log.info("TestLog ----------- Initiate successful upgrade -------------");
|
||||||
successfulUpgradeMonitor.run();
|
successfulUpgradeMonitor.run();
|
||||||
log.info("TestLog ----------- successful upgrade done -------------");
|
log.info("TestLog ----------- successful upgrade done -------------");
|
||||||
Assertions.assertEquals(ClientVersion.CLIENT_VERSION_3x, stateMachineUnderTest.getCurrentClientVersion());
|
Assertions.assertEquals(ClientVersion.CLIENT_VERSION_3X, stateMachineUnderTest.getCurrentClientVersion());
|
||||||
verify(mockInitializer).initializeClientVersionFor3x(ClientVersion.CLIENT_VERSION_3x_WITH_ROLLBACK);
|
verify(mockInitializer).initializeClientVersionFor3x(ClientVersion.CLIENT_VERSION_3X_WITH_ROLLBACK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue