Remove dynamic configuration feature flags; add `DynamicMessagePersisterConfiguration`

This commit is contained in:
Chris Eager 2022-07-27 13:59:46 -05:00 committed by Chris Eager
parent 41a113e22c
commit a6f9409a39
5 changed files with 78 additions and 42 deletions

View File

@ -5,7 +5,6 @@ import com.google.common.annotations.VisibleForTesting;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import javax.validation.Valid; import javax.validation.Valid;
public class DynamicConfiguration { public class DynamicConfiguration {
@ -30,9 +29,6 @@ public class DynamicConfiguration {
@Valid @Valid
private DynamicPaymentsConfiguration payments = new DynamicPaymentsConfiguration(); private DynamicPaymentsConfiguration payments = new DynamicPaymentsConfiguration();
@JsonProperty
private Set<String> featureFlags = Collections.emptySet();
@JsonProperty @JsonProperty
@Valid @Valid
private DynamicTwilioConfiguration twilio = new DynamicTwilioConfiguration(); private DynamicTwilioConfiguration twilio = new DynamicTwilioConfiguration();
@ -64,6 +60,10 @@ public class DynamicConfiguration {
@Valid @Valid
DynamicAbusiveHostRulesConfiguration abusiveHostRules = new DynamicAbusiveHostRulesConfiguration(); DynamicAbusiveHostRulesConfiguration abusiveHostRules = new DynamicAbusiveHostRulesConfiguration();
@JsonProperty
@Valid
DynamicMessagePersisterConfiguration messagePersister = new DynamicMessagePersisterConfiguration();
public Optional<DynamicExperimentEnrollmentConfiguration> getExperimentEnrollmentConfiguration( public Optional<DynamicExperimentEnrollmentConfiguration> getExperimentEnrollmentConfiguration(
final String experimentName) { final String experimentName) {
return Optional.ofNullable(experiments.get(experimentName)); return Optional.ofNullable(experiments.get(experimentName));
@ -86,10 +86,6 @@ public class DynamicConfiguration {
return payments; return payments;
} }
public Set<String> getActiveFeatureFlags() {
return featureFlags;
}
public DynamicTwilioConfiguration getTwilioConfiguration() { public DynamicTwilioConfiguration getTwilioConfiguration() {
return twilio; return twilio;
} }
@ -115,7 +111,9 @@ public class DynamicConfiguration {
return pushLatency; return pushLatency;
} }
public DynamicUakMigrationConfiguration getUakMigrationConfiguration() { return uakMigrationConfiguration; } public DynamicUakMigrationConfiguration getUakMigrationConfiguration() {
return uakMigrationConfiguration;
}
public DynamicTurnConfiguration getTurnConfiguration() { public DynamicTurnConfiguration getTurnConfiguration() {
return turn; return turn;
@ -124,4 +122,8 @@ public class DynamicConfiguration {
public DynamicAbusiveHostRulesConfiguration getAbusiveHostRules() { public DynamicAbusiveHostRulesConfiguration getAbusiveHostRules() {
return abusiveHostRules; return abusiveHostRules;
} }
public DynamicMessagePersisterConfiguration getMessagePersisterConfiguration() {
return messagePersister;
}
} }

View File

@ -0,0 +1,18 @@
/*
* Copyright 2022 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration.dynamic;
import com.fasterxml.jackson.annotation.JsonProperty;
public class DynamicMessagePersisterConfiguration {
@JsonProperty
private boolean persistenceEnabled = true;
public boolean isPersistenceEnabled() {
return persistenceEnabled;
}
}

View File

@ -50,7 +50,6 @@ public class MessagePersister implements Managed {
private static final long EXCEPTION_PAUSE_MILLIS = Duration.ofSeconds(3).toMillis(); private static final long EXCEPTION_PAUSE_MILLIS = Duration.ofSeconds(3).toMillis();
private static final String DISABLE_PERSISTER_FEATURE_FLAG = "DISABLE_MESSAGE_PERSISTER";
private static final int WORKER_THREAD_COUNT = 4; private static final int WORKER_THREAD_COUNT = 4;
private static final int CONSECUTIVE_EMPTY_CACHE_REMOVAL_LIMIT = 3; private static final int CONSECUTIVE_EMPTY_CACHE_REMOVAL_LIMIT = 3;
@ -69,10 +68,8 @@ public class MessagePersister implements Managed {
for (int i = 0; i < workerThreads.length; i++) { for (int i = 0; i < workerThreads.length; i++) {
workerThreads[i] = new Thread(() -> { workerThreads[i] = new Thread(() -> {
while (running) { while (running) {
if (dynamicConfigurationManager.getConfiguration().getActiveFeatureFlags() if (dynamicConfigurationManager.getConfiguration().getMessagePersisterConfiguration()
.contains(DISABLE_PERSISTER_FEATURE_FLAG)) { .isPersistenceEnabled()) {
Util.sleep(1000);
} else {
try { try {
final int queuesPersisted = persistNextQueues(Instant.now()); final int queuesPersisted = persistNextQueues(Instant.now());
queueCountHistogram.update(queuesPersisted); queueCountHistogram.update(queuesPersisted);
@ -84,6 +81,8 @@ public class MessagePersister implements Managed {
logger.warn("Failed to persist queues", t); logger.warn("Failed to persist queues", t);
Util.sleep(EXCEPTION_PAUSE_MILLIS); Util.sleep(EXCEPTION_PAUSE_MILLIS);
} }
} else {
Util.sleep(1000);
} }
} }
}, "MessagePersisterWorker-" + i); }, "MessagePersisterWorker-" + i);

View File

@ -201,29 +201,6 @@ class DynamicConfigurationTest {
} }
} }
@Test
void testParseFeatureFlags() throws JsonProcessingException {
{
final String emptyConfigYaml = REQUIRED_CONFIG.concat("test: true");
final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertTrue(emptyConfig.getActiveFeatureFlags().isEmpty());
}
{
final String featureFlagYaml = REQUIRED_CONFIG.concat("""
featureFlags:
- testFlag
""");
final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(featureFlagYaml, DynamicConfiguration.class).orElseThrow();
assertTrue(emptyConfig.getActiveFeatureFlags().contains("testFlag"));
}
}
@Test @Test
void testParseTwilioConfiguration() throws JsonProcessingException { void testParseTwilioConfiguration() throws JsonProcessingException {
{ {
@ -435,6 +412,43 @@ class DynamicConfigurationTest {
assertThat(turnConfiguration.getUriConfigs().get(1).getEnrolledNumbers()).containsExactly("+15555555555"); assertThat(turnConfiguration.getUriConfigs().get(1).getEnrolledNumbers()).containsExactly("+15555555555");
} }
} }
@Test
void testMessagePersister() throws JsonProcessingException {
{
final String emptyConfigYaml = REQUIRED_CONFIG.concat("test: true");
final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertTrue(emptyConfig.getMessagePersisterConfiguration().isPersistenceEnabled());
}
{
final String messagePersisterEnabledYaml = REQUIRED_CONFIG.concat("""
messagePersister:
persistenceEnabled: true
""");
final DynamicConfiguration config =
DynamicConfigurationManager.parseConfiguration(messagePersisterEnabledYaml, DynamicConfiguration.class)
.orElseThrow();
assertTrue(config.getMessagePersisterConfiguration().isPersistenceEnabled());
}
{
final String messagePersisterDisabledYaml = REQUIRED_CONFIG.concat("""
messagePersister:
persistenceEnabled: false
""");
final DynamicConfiguration config =
DynamicConfigurationManager.parseConfiguration(messagePersisterDisabledYaml, DynamicConfiguration.class)
.orElseThrow();
assertFalse(config.getMessagePersisterConfiguration().isPersistenceEnabled());
}
}
} }

View File

@ -120,8 +120,9 @@ class DynamicConfigurationManagerTest {
configurationToken("1").build())) configurationToken("1").build()))
.thenReturn(GetLatestConfigurationResponse.builder() .thenReturn(GetLatestConfigurationResponse.builder()
.configuration(SdkBytes.fromUtf8String(""" .configuration(SdkBytes.fromUtf8String("""
featureFlags: experiments:
- testFlag test:
enrollmentPercentage: 50
captcha: captcha:
scoreFloor: 1.0 scoreFloor: 1.0
""")) """))
@ -139,10 +140,12 @@ class DynamicConfigurationManagerTest {
assertTimeoutPreemptively(Duration.ofSeconds(5), () -> { assertTimeoutPreemptively(Duration.ofSeconds(5), () -> {
// we should eventually get the updated config (or the test will timeout) // we should eventually get the updated config (or the test will timeout)
dynamicConfigurationManager.start(); dynamicConfigurationManager.start();
while (dynamicConfigurationManager.getConfiguration().getActiveFeatureFlags().isEmpty()) { while (dynamicConfigurationManager.getConfiguration().getExperimentEnrollmentConfiguration("test").isEmpty()) {
Thread.sleep(100); Thread.sleep(100);
} }
assertThat(dynamicConfigurationManager.getConfiguration().getActiveFeatureFlags()).containsExactly("testFlag"); assertThat(
dynamicConfigurationManager.getConfiguration().getExperimentEnrollmentConfiguration("test").get()
.getEnrollmentPercentage()).isEqualTo(50);
}); });
} }