Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

specify refresh interval as duration #88

Merged
merged 1 commit into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
* A {@link ConfigurationRepository} implementation supporting a file on
Expand All @@ -36,12 +36,12 @@ public class FileSystemConfigurationRepository implements ConfigurationRepositor
private final LoadingCache<String, Map<String, Configuration<?>>> cachedConfigurations;
private final String fileName;

FileSystemConfigurationRepository(final String fileName, long refreshIntervalInSeconds, final ConfigurationParser configurationParser) {
FileSystemConfigurationRepository(final String fileName, Duration refreshInterval, final ConfigurationParser configurationParser) {
this.fileName = fileName;
this.configurationParser = configurationParser;

cachedConfigurations = CacheBuilder.newBuilder()
.refreshAfterWrite(refreshIntervalInSeconds, TimeUnit.SECONDS)
.refreshAfterWrite(refreshInterval)
.build(new CacheLoader<>() {
@Override
public Map<String, Configuration<?>> load(String filename) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.fasterxml.jackson.databind.ObjectMapper;

import java.time.Duration;

import static java.util.Objects.requireNonNull;

/**
Expand All @@ -12,7 +14,7 @@
public class FileSystemConfigurationRepositoryBuilder {

private String filePath;
private long refreshIntervalInSeconds = 60L;
private Duration refreshInterval = Duration.ofMinutes(1);
private ObjectMapper objectMapper;
private final ConfigurationParser configurationParser;

Expand All @@ -31,9 +33,11 @@ public FileSystemConfigurationRepositoryBuilder fileName(String filePath) {
/**
* @param refreshIntervalInSeconds The number of seconds between the starts of subsequent runs to refresh
* the configuration.
* <p>
* {@code @Deprecated} use {@link S3ConfigurationRepositoryBuilder#refreshInterval(Duration)} instead
*/
public FileSystemConfigurationRepositoryBuilder refreshIntervalInSeconds(long refreshIntervalInSeconds) {
this.refreshIntervalInSeconds = refreshIntervalInSeconds;
this.refreshInterval = Duration.ofSeconds(refreshIntervalInSeconds);
return this;
}

Expand All @@ -45,13 +49,21 @@ public FileSystemConfigurationRepositoryBuilder objectMapper(ObjectMapper object
return this;
}

/**
* @param refreshInterval The interval between the starts of subsequent runs to refresh the configuration.
*/
public FileSystemConfigurationRepositoryBuilder refreshInterval(Duration refreshInterval) {
this.refreshInterval = refreshInterval;
return this;
}

public FileSystemConfigurationRepository build() {
requireNonNull(filePath, "filePath must not be null");

if (objectMapper != null) {
configurationParser.setObjectMapper(objectMapper);
}

return new FileSystemConfigurationRepository(filePath, refreshIntervalInSeconds, configurationParser);
return new FileSystemConfigurationRepository(filePath, refreshInterval, configurationParser);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.zalando.baigan.repository.aws.S3FileLoader;

import javax.annotation.Nonnull;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand All @@ -28,16 +29,16 @@ public class S3ConfigurationRepository implements ConfigurationRepository {

private final ConfigurationParser configurationParser;
private final S3FileLoader s3Loader;
private final long refreshInterval;
private final Duration refreshInterval;
private final ScheduledExecutorService executor;
private volatile Map<String, Configuration<?>> configurationsMap = ImmutableMap.of();

S3ConfigurationRepository(@Nonnull final String bucketName, @Nonnull final String key,
final long refreshInterval, final ScheduledExecutorService executor,
final Duration refreshInterval, final ScheduledExecutorService executor,
final AmazonS3 s3Client, final AWSKMS kmsClient, ConfigurationParser configurationParser) {
checkNotNull(bucketName, "bucketName is required");
checkNotNull(key, "key is required");
checkArgument(refreshInterval >= 0, "refreshInterval has to be >= 0");
checkArgument(!refreshInterval.isNegative(), "refreshInterval has to be >= 0");
checkNotNull(executor, "executor is required");
checkNotNull(s3Client, "s3Client is required");
checkNotNull(kmsClient, "kmsClient is required");
Expand All @@ -48,7 +49,7 @@ public class S3ConfigurationRepository implements ConfigurationRepository {
this.configurationParser = configurationParser;

loadConfigurations();
if (refreshInterval > 0) {
if (!refreshInterval.isZero()) {
setupRefresh();
}
}
Expand Down Expand Up @@ -85,9 +86,9 @@ private void setupRefresh() {
LOG.error("Failed to refresh configuration, keeping old state.", e);
}
},
this.refreshInterval,
this.refreshInterval,
TimeUnit.SECONDS
this.refreshInterval.toMillis(),
this.refreshInterval.toMillis(),
TimeUnit.MILLISECONDS
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.annotation.Nonnull;
import java.time.Duration;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;

Expand All @@ -26,7 +27,7 @@ public class S3ConfigurationRepositoryBuilder {
private ScheduledExecutorService executor;
private AmazonS3 s3Client;
private AWSKMS kmsClient;
private long refreshIntervalInSeconds = 60;
private Duration refreshInterval = Duration.ofMinutes(1);
private String bucketName;
private String key;
private ObjectMapper objectMapper;
Expand Down Expand Up @@ -75,9 +76,12 @@ public S3ConfigurationRepositoryBuilder key(@Nonnull final String key) {
/**
* @param refreshIntervalInSeconds The number of seconds between the starts of subsequent runs to refresh
* the configuration
* <p>
* {@code @Deprecated} use {@link S3ConfigurationRepositoryBuilder#refreshInterval(Duration)} instead
*/
@Deprecated
public S3ConfigurationRepositoryBuilder refreshIntervalInSeconds(final long refreshIntervalInSeconds) {
this.refreshIntervalInSeconds = refreshIntervalInSeconds;
this.refreshInterval = Duration.ofSeconds(refreshIntervalInSeconds);
return this;
}

Expand All @@ -98,6 +102,14 @@ public S3ConfigurationRepositoryBuilder objectMapper(ObjectMapper objectMapper)
return this;
}

/**
* @param refreshInterval The interval between the starts of subsequent runs to refresh the configuration.
*/
public S3ConfigurationRepositoryBuilder refreshInterval(Duration refreshInterval) {
this.refreshInterval = refreshInterval;
return this;
}

public S3ConfigurationRepository build() {
if (executor == null) {
executor = new ScheduledThreadPoolExecutor(1);
Expand All @@ -112,6 +124,6 @@ public S3ConfigurationRepository build() {
configurationParser.setObjectMapper(objectMapper);
}

return new S3ConfigurationRepository(bucketName, key, refreshIntervalInSeconds, executor, s3Client, kmsClient, configurationParser);
return new S3ConfigurationRepository(bucketName, key, refreshInterval, executor, s3Client, kmsClient, configurationParser);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.UUID;
Expand All @@ -40,14 +41,17 @@ public class FileSystemConfigurationRepositoryEnd2EndIT {
@Autowired
private Path configFile;

private static final Duration CONFIG_REFRESH_INTERVAL = Duration.ofMillis(100);
private static final long TIME_TO_WAIT_FOR_CONFIG_REFRESH = CONFIG_REFRESH_INTERVAL.plusMillis(100).toMillis();

@Test
public void givenAConfigurationFile_whenConfigurationIsChanged_thenConfigurationBeanReturnsNewConfigAfterRefreshTime() throws InterruptedException, IOException {
assertThat(someConfiguration.isThisTrue(), nullValue());
assertThat(someConfiguration.someValue(), nullValue());
assertThat(someConfiguration.someConfig(), nullValue());

Files.writeString(configFile, "[{\"alias\": \"some.configuration.some.value\", \"defaultValue\": \"some value\"}]");
Thread.sleep(1100);
Thread.sleep(TIME_TO_WAIT_FOR_CONFIG_REFRESH);
assertThat(someConfiguration.isThisTrue(), nullValue());
assertThat(someConfiguration.someValue(), equalTo("some value"));
assertThat(someConfiguration.someConfig(), nullValue());
Expand All @@ -61,7 +65,7 @@ public void givenAConfigurationFile_whenConfigurationIsChanged_thenConfiguration
"}}, " +
"{ \"alias\": \"some.configuration.config.list\", \"defaultValue\": [\"A\",\"B\"]}]"
);
Thread.sleep(1100);
Thread.sleep(TIME_TO_WAIT_FOR_CONFIG_REFRESH);
assertThat(someConfiguration.isThisTrue(), equalTo(true));
assertThat(someConfiguration.someValue(), equalTo("some value"));
assertThat(someConfiguration.someConfig(), equalTo(new SomeConfigObject("a value")));
Expand All @@ -74,12 +78,12 @@ public void givenAConfigurationFile_whenTheFileIsUpdatedWithInvalidConfig_thenTh
"{ \"alias\": \"some.configuration.is.this.true\", \"defaultValue\": true}, " +
"{ \"alias\": \"some.configuration.some.value\", \"defaultValue\": \"some value\"}]"
);
Thread.sleep(1100);
Thread.sleep(TIME_TO_WAIT_FOR_CONFIG_REFRESH);
assertThat(someConfiguration.isThisTrue(), equalTo(true));
assertThat(someConfiguration.someValue(), equalTo("some value"));

Files.writeString(configFile, "{invalid: \"configuration]");
Thread.sleep(1100);
Thread.sleep(200);
assertThat(someConfiguration.isThisTrue(), equalTo(true));
assertThat(someConfiguration.someValue(), equalTo("some value"));
}
Expand All @@ -90,7 +94,7 @@ public void givenAConfigurationFile_whenConfigurationTypeIsGeneric_thenDeseriali
"\"a8a23682-1623-450b-8817-50c98827ea4e\": [{\"config_key\":\"A\"}]," +
"\"76ced443-6555-4748-a22e-8700f3864e59\": [{\"config_key\":\"B\"}]}" +
"}]");
Thread.sleep(1100);
Thread.sleep(TIME_TO_WAIT_FOR_CONFIG_REFRESH);
assertThat(someConfiguration.topLevelGenerics(), equalTo(Map.of(
UUID.fromString("a8a23682-1623-450b-8817-50c98827ea4e"), List.of(new SomeConfigObject("A")),
UUID.fromString("76ced443-6555-4748-a22e-8700f3864e59"), List.of(new SomeConfigObject("B"))
Expand All @@ -106,7 +110,7 @@ static class RepoConfig {
FileSystemConfigurationRepository configurationRepository(Path configFile, RepositoryFactory repositoryFactory) {
return repositoryFactory.fileSystemConfigurationRepository()
.fileName(configFile.toString())
.refreshIntervalInSeconds(1)
.refreshInterval(CONFIG_REFRESH_INTERVAL)
.objectMapper(new ObjectMapper().configure(FAIL_ON_UNKNOWN_PROPERTIES, false))
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.zalando.baigan.repository.RepositoryFactory;
import org.zalando.baigan.repository.S3ConfigurationRepository;

import java.time.Duration;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;

Expand All @@ -47,6 +48,9 @@ public class S3ConfigurationRepositoryEnd2EndIT {
public static final String S3_CONFIG_BUCKET = "some-bucket";
public static final String S3_CONFIG_KEY = "some-key";

private static final Duration CONFIG_REFRESH_INTERVAL = Duration.ofMillis(100);
private static final long TIME_TO_WAIT_FOR_CONFIG_REFRESH = CONFIG_REFRESH_INTERVAL.plusMillis(100).toMillis();

@Autowired
private AmazonS3 s3;

Expand All @@ -69,7 +73,7 @@ public void givenS3Configuration_whenConfigurationIsChangedOnS3_thenConfiguratio
S3_CONFIG_KEY,
"[{\"alias\": \"some.configuration.some.value\", \"defaultValue\": \"some value\"}]"
);
Thread.sleep(1100);
Thread.sleep(TIME_TO_WAIT_FOR_CONFIG_REFRESH);
assertThat(someConfiguration.isThisTrue(), nullValue());
assertThat(someConfiguration.someValue(), equalTo("some value"));
assertThat(someConfiguration.someConfig(), nullValue());
Expand All @@ -84,7 +88,7 @@ public void givenS3Configuration_whenConfigurationIsChangedOnS3_thenConfiguratio
"{ \"alias\": \"some.configuration.some.value\", \"defaultValue\": \"some value\"}, " +
"{ \"alias\": \"some.configuration.config.list\", \"defaultValue\": [\"A\",\"B\"]}]"
);
Thread.sleep(1100);
Thread.sleep(TIME_TO_WAIT_FOR_CONFIG_REFRESH);
assertThat(someConfiguration.someConfig(), equalTo(new SomeConfigObject("a value")));
assertThat(someConfiguration.isThisTrue(), equalTo(true));
assertThat(someConfiguration.someValue(), equalTo("some value"));
Expand All @@ -99,7 +103,7 @@ public void givenS3Configuration_whenTheS3FileIsUpdatedWithInvalidConfig_thenThe
"[{\"alias\": \"some.configuration.is.this.true\", \"defaultValue\": true}, " +
"{\"alias\": \"some.configuration.some.value\", \"defaultValue\": \"some value\"}]"
);
Thread.sleep(1100);
Thread.sleep(TIME_TO_WAIT_FOR_CONFIG_REFRESH);
assertThat(someConfiguration.isThisTrue(), equalTo(true));
assertThat(someConfiguration.someValue(), equalTo("some value"));

Expand All @@ -108,7 +112,7 @@ public void givenS3Configuration_whenTheS3FileIsUpdatedWithInvalidConfig_thenThe
S3_CONFIG_KEY,
"an: invalid\"} config"
);
Thread.sleep(1100);
Thread.sleep(TIME_TO_WAIT_FOR_CONFIG_REFRESH);
assertThat(someConfiguration.isThisTrue(), equalTo(true));
assertThat(someConfiguration.someValue(), equalTo("some value"));
}
Expand Down Expand Up @@ -141,7 +145,7 @@ S3ConfigurationRepository configurationRepository(
.key(S3_CONFIG_KEY)
.s3Client(amazonS3)
.kmsClient(kms)
.refreshIntervalInSeconds(1)
.refreshInterval(CONFIG_REFRESH_INTERVAL)
.executor(executorService)
.build();
}
Expand Down