Migrate DynamicConfigurationManager to use java.util.concurrent

This commit is contained in:
Chris Eager
2024-03-07 09:01:34 -06:00
committed by Chris Eager
parent 9e510a678c
commit 3dadaf9334
5 changed files with 47 additions and 38 deletions

View File

@@ -315,11 +315,14 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
UncaughtExceptionHandler.register();
ScheduledExecutorService dynamicConfigurationExecutor = environment.lifecycle()
.scheduledExecutorService(name(getClass(), "dynamicConfiguration-%d")).threads(1).build();
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager =
new DynamicConfigurationManager<>(config.getAppConfig().getApplication(),
config.getAppConfig().getEnvironment(),
config.getAppConfig().getConfigurationName(),
DynamicConfiguration.class);
DynamicConfiguration.class, dynamicConfigurationExecutor);
dynamicConfigurationManager.start();
MetricsUtil.configureRegistries(config, environment, dynamicConfigurationManager);

View File

@@ -13,6 +13,9 @@ import io.micrometer.core.instrument.Metrics;
import java.time.Duration;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
@@ -38,8 +41,9 @@ public class DynamicConfigurationManager<T> {
// Set on initial config fetch
private final AtomicReference<T> configuration = new AtomicReference<>();
private final CountDownLatch initialized = new CountDownLatch(1);
private final ScheduledExecutorService scheduledExecutorService;
private String configurationToken = null;
private boolean initialized = false;
private static final Validator VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();
@@ -50,61 +54,48 @@ public class DynamicConfigurationManager<T> {
private static final Logger logger = LoggerFactory.getLogger(DynamicConfigurationManager.class);
public DynamicConfigurationManager(String application, String environment, String configurationName,
Class<T> configurationClass) {
Class<T> configurationClass, ScheduledExecutorService scheduledExecutorService) {
this(AppConfigDataClient
.builder()
.overrideConfiguration(ClientOverrideConfiguration.builder()
.apiCallTimeout(Duration.ofSeconds(10))
.apiCallAttemptTimeout(Duration.ofSeconds(10)).build())
.build(),
application, environment, configurationName, configurationClass);
application, environment, configurationName, configurationClass, scheduledExecutorService);
}
@VisibleForTesting
DynamicConfigurationManager(AppConfigDataClient appConfigClient, String application, String environment,
String configurationName, Class<T> configurationClass) {
String configurationName, Class<T> configurationClass, ScheduledExecutorService scheduledExecutorService) {
this.appConfigClient = appConfigClient;
this.application = application;
this.environment = environment;
this.configurationName = configurationName;
this.configurationClass = configurationClass;
this.scheduledExecutorService = scheduledExecutorService;
}
public T getConfiguration() {
synchronized (this) {
while (!initialized) {
try {
this.wait();
} catch (final InterruptedException e) {
logger.warn("Interrupted while waiting for initial configuration", e);
throw new RuntimeException(e);
}
}
try {
initialized.await();
} catch (InterruptedException e) {
logger.warn("Interrupted while waiting for initial configuration", e);
throw new RuntimeException(e);
}
return configuration.get();
}
public void start() {
configuration.set(retrieveInitialDynamicConfiguration());
synchronized (this) {
this.initialized = true;
this.notifyAll();
}
initialized.countDown();
final Thread workerThread = new Thread(() -> {
while (true) {
try {
retrieveDynamicConfiguration().ifPresent(configuration::set);
} catch (Exception e) {
logger.warn("Error retrieving dynamic configuration", e);
}
Util.sleep(5000);
scheduledExecutorService.scheduleWithFixedDelay(() -> {
try {
retrieveDynamicConfiguration().ifPresent(configuration::set);
} catch (Exception e) {
logger.warn("Error retrieving dynamic configuration", e);
}
}, "DynamicConfigurationManagerWorker");
workerThread.setDaemon(true);
workerThread.start();
}, 0, 5, TimeUnit.SECONDS);
}
private Optional<T> retrieveDynamicConfiguration() throws JsonProcessingException {

View File

@@ -98,6 +98,14 @@ public class AssignUsernameCommand extends EnvironmentCommand<WhisperServerConfi
throws Exception {
environment.getObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ScheduledExecutorService dynamicConfigurationExecutor = environment.lifecycle()
.scheduledExecutorService(name(getClass(), "dynamicConfiguration-%d")).threads(1).build();
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class, dynamicConfigurationExecutor);
dynamicConfigurationManager.start();
ClientResources redisClusterClientResources = ClientResources.builder().build();
FaultTolerantRedisCluster cacheCluster = new FaultTolerantRedisCluster("main_cache_cluster",
@@ -128,11 +136,6 @@ public class AssignUsernameCommand extends EnvironmentCommand<WhisperServerConfi
ExternalServiceCredentialsGenerator secureValueRecoveryCredentialsGenerator = SecureValueRecovery2Controller.credentialsGenerator(
configuration.getSvr2Configuration());
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class);
dynamicConfigurationManager.start();
ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(
dynamicConfigurationManager);

View File

@@ -72,9 +72,12 @@ record CommandDependencies(
environment.getObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ScheduledExecutorService dynamicConfigurationExecutor = environment.lifecycle()
.scheduledExecutorService(name(name, "dynamicConfiguration-%d")).threads(1).build();
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class);
configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class, dynamicConfigurationExecutor);
dynamicConfigurationManager.start();
MetricsUtil.configureRegistries(configuration, environment, dynamicConfigurationManager);