Migrate DynamicConfigurationManager to use java.util.concurrent
This commit is contained in:
parent
9e510a678c
commit
3dadaf9334
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -6,6 +6,9 @@ import static org.mockito.Mockito.mock;
|
|||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
|
@ -27,12 +30,13 @@ class DynamicConfigurationManagerTest {
|
|||
private DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
|
||||
private AppConfigDataClient appConfig;
|
||||
private StartConfigurationSessionRequest startConfigurationSession;
|
||||
private final ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1);
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.appConfig = mock(AppConfigDataClient.class);
|
||||
this.dynamicConfigurationManager = new DynamicConfigurationManager<>(
|
||||
appConfig, "foo", "bar", "baz", DynamicConfiguration.class);
|
||||
appConfig, "foo", "bar", "baz", DynamicConfiguration.class, scheduledExecutorService);
|
||||
this.startConfigurationSession = StartConfigurationSessionRequest.builder()
|
||||
.applicationIdentifier("foo")
|
||||
.environmentIdentifier("bar")
|
||||
|
@ -40,6 +44,11 @@ class DynamicConfigurationManagerTest {
|
|||
.build();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void teardown() {
|
||||
scheduledExecutorService.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetInitialConfig() {
|
||||
when(appConfig.startConfigurationSession(startConfigurationSession))
|
||||
|
|
Loading…
Reference in New Issue