Skip to content

Commit

Permalink
Switch Redis extension to @ConfigMapping
Browse files Browse the repository at this point in the history
  • Loading branch information
gsmet committed May 25, 2023
1 parent b83f96c commit edda14a
Show file tree
Hide file tree
Showing 14 changed files with 337 additions and 376 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package io.quarkus.redis.client.deployment;

import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;

import io.quarkus.runtime.annotations.ConfigGroup;
import io.quarkus.runtime.annotations.ConfigItem;
import io.smallrye.config.WithDefault;

@ConfigGroup
public class DevServicesConfig {
public interface DevServicesConfig {

/**
* If DevServices has been explicitly enabled or disabled. DevServices is generally enabled
Expand All @@ -17,24 +16,22 @@ public class DevServicesConfig {
* When DevServices is enabled Quarkus will attempt to automatically configure and start
* a database when running in Dev or Test mode and when Docker is running.
*/
@ConfigItem(defaultValue = "true")
public boolean enabled;
@WithDefault("true")
boolean enabled();

/**
* The container image name to use, for container based DevServices providers.
* If you want to use Redis Stack modules (bloom, graph, search...), use:
* {@code redis/redis-stack-server:latest}.
*/
@ConfigItem
public Optional<String> imageName;
Optional<String> imageName();

/**
* Optional fixed port the dev service will listen to.
* <p>
* If not defined, the port will be chosen randomly.
*/
@ConfigItem
public OptionalInt port;
OptionalInt port();

/**
* Indicates if the Redis server managed by Quarkus Dev Services is shared.
Expand All @@ -47,8 +44,8 @@ public class DevServicesConfig {
* <p>
* Container sharing is only used in dev mode.
*/
@ConfigItem(defaultValue = "true")
public boolean shared;
@WithDefault("true")
boolean shared();

/**
* The value of the {@code quarkus-dev-service-redis} label attached to the started container.
Expand All @@ -60,25 +57,6 @@ public class DevServicesConfig {
* <p>
* This property is used when you need multiple shared Redis servers.
*/
@ConfigItem(defaultValue = "redis")
public String serviceName;

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
DevServicesConfig that = (DevServicesConfig) o;
return enabled == that.enabled &&
Objects.equals(imageName, that.imageName) &&
Objects.equals(port, that.port) &&
Objects.equals(shared, that.shared) &&
Objects.equals(serviceName, that.serviceName);
}

@Override
public int hashCode() {
return Objects.hash(enabled, imageName, port, shared, serviceName);
}
@WithDefault("redis")
String serviceName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ public List<DevServicesResultBuildItem> startRedisContainers(LaunchModeBuildItem
LoggingSetupBuildItem loggingSetupBuildItem,
GlobalDevServicesConfig devServicesConfig) {

Map<String, DevServiceConfiguration> currentDevServicesConfiguration = new HashMap<>(config.additionalDevServices);
currentDevServicesConfiguration.put(RedisConfig.DEFAULT_CLIENT_NAME, config.defaultDevService);
Map<String, DevServiceConfiguration> currentDevServicesConfiguration = new HashMap<>(config.additionalDevServices());
currentDevServicesConfiguration.put(RedisConfig.DEFAULT_CLIENT_NAME, config.defaultDevService());

// figure out if we need to shut down and restart existing redis containers
// if not and the redis containers have already started we just return
Expand Down Expand Up @@ -101,7 +101,7 @@ public List<DevServicesResultBuildItem> startRedisContainers(LaunchModeBuildItem
for (Entry<String, DevServiceConfiguration> entry : currentDevServicesConfiguration.entrySet()) {
String connectionName = entry.getKey();
RunningDevService devService = startContainer(dockerStatusBuildItem, connectionName,
entry.getValue().devservices,
entry.getValue().devservices(),
launchMode.getLaunchMode(),
!devServicesSharedNetworkBuildItem.isEmpty(), devServicesConfig.timeout);
if (devService == null) {
Expand Down Expand Up @@ -148,7 +148,7 @@ public List<DevServicesResultBuildItem> startRedisContainers(LaunchModeBuildItem
private RunningDevService startContainer(DockerStatusBuildItem dockerStatusBuildItem, String name,
DevServicesConfig devServicesConfig, LaunchMode launchMode,
boolean useSharedNetwork, Optional<Duration> timeout) {
if (!devServicesConfig.enabled) {
if (!devServicesConfig.enabled()) {
// explicitly disabled
log.debug("Not starting devservices for " + (RedisConfig.isDefaultClient(name) ? "default redis client" : name)
+ " as it has been disabled in the config");
Expand All @@ -171,20 +171,20 @@ private RunningDevService startContainer(DockerStatusBuildItem dockerStatusBuild
return null;
}

DockerImageName dockerImageName = DockerImageName.parse(devServicesConfig.imageName.orElse(REDIS_7_ALPINE))
DockerImageName dockerImageName = DockerImageName.parse(devServicesConfig.imageName().orElse(REDIS_7_ALPINE))
.asCompatibleSubstituteFor(REDIS_7_ALPINE);

Supplier<RunningDevService> defaultRedisServerSupplier = () -> {
QuarkusPortRedisContainer redisContainer = new QuarkusPortRedisContainer(dockerImageName, devServicesConfig.port,
launchMode == DEVELOPMENT ? devServicesConfig.serviceName : null, useSharedNetwork);
QuarkusPortRedisContainer redisContainer = new QuarkusPortRedisContainer(dockerImageName, devServicesConfig.port(),
launchMode == DEVELOPMENT ? devServicesConfig.serviceName() : null, useSharedNetwork);
timeout.ifPresent(redisContainer::withStartupTimeout);
redisContainer.start();
String redisHost = REDIS_SCHEME + redisContainer.getHost() + ":" + redisContainer.getPort();
return new RunningDevService(Feature.REDIS_CLIENT.getName(), redisContainer.getContainerId(),
redisContainer::close, configPrefix + RedisConfig.HOSTS_CONFIG_NAME, redisHost);
};

return redisContainerLocator.locateContainer(devServicesConfig.serviceName, devServicesConfig.shared, launchMode)
return redisContainerLocator.locateContainer(devServicesConfig.serviceName(), devServicesConfig.shared(), launchMode)
.map(containerAddress -> {
String redisUrl = REDIS_SCHEME + containerAddress.getUrl();
return new RunningDevService(Feature.REDIS_CLIENT.getName(), containerAddress.getId(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
package io.quarkus.redis.client.deployment;

import java.util.Map;
import java.util.Objects;

import io.quarkus.runtime.annotations.ConfigDocMapKey;
import io.quarkus.runtime.annotations.ConfigGroup;
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;
import io.smallrye.config.WithName;
import io.smallrye.config.WithParentName;

@ConfigRoot
public class RedisBuildTimeConfig {
@ConfigMapping(prefix = "quarkus.redis")
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
public interface RedisBuildTimeConfig {

/**
* The default redis client
*/
@ConfigItem(name = ConfigItem.PARENT)
public RedisClientBuildTimeConfig defaultRedisClient;
@WithParentName
RedisClientBuildTimeConfig defaultRedisClient();

/**
* Configures additional (named) Redis clients.
Expand Down Expand Up @@ -44,52 +48,37 @@ public class RedisBuildTimeConfig {
* }
* </pre>
*/
@ConfigItem(name = ConfigItem.PARENT)
@WithParentName
@ConfigDocMapKey("redis-client-name")
public Map<String, RedisClientBuildTimeConfig> namedRedisClients;
Map<String, RedisClientBuildTimeConfig> namedRedisClients();

/**
* Whether a health check is published in case the smallrye-health extension is present.
*/
@ConfigItem(name = "health.enabled", defaultValue = "true")
public boolean healthEnabled;
@WithName("health.enabled")
@WithDefault("true")
boolean healthEnabled();

/**
* Default Dev services configuration.
*/
@ConfigItem(name = ConfigItem.PARENT)
public DevServiceConfiguration defaultDevService;
@WithParentName
DevServiceConfiguration defaultDevService();

/**
* Additional dev services configurations
*/
@ConfigItem(name = ConfigItem.PARENT)
@WithParentName
@ConfigDocMapKey("additional-redis-clients")
public Map<String, DevServiceConfiguration> additionalDevServices;
Map<String, DevServiceConfiguration> additionalDevServices();

@ConfigGroup
public static class DevServiceConfiguration {
public interface DevServiceConfiguration {
/**
* Configuration for DevServices
* <p>
* DevServices allows Quarkus to automatically start Redis in dev and test mode.
*/
@ConfigItem
public DevServicesConfig devservices;

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
DevServiceConfiguration that = (DevServiceConfiguration) o;
return Objects.equals(devservices, that.devservices);
}

@Override
public int hashCode() {
return Objects.hash(devservices);
}
DevServicesConfig devservices();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
import java.util.List;
import java.util.Optional;

import io.quarkus.runtime.annotations.ConfigDocDefault;
import io.quarkus.runtime.annotations.ConfigGroup;
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConvertWith;
import io.quarkus.runtime.configuration.TrimmedStringConverter;
import io.smallrye.config.WithConverter;
import io.smallrye.config.WithDefault;

@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@ConfigGroup
public class RedisClientBuildTimeConfig {
public interface RedisClientBuildTimeConfig {

/**
* A list of files allowing to pre-load data into the Redis server.
Expand All @@ -23,20 +23,20 @@ public class RedisClientBuildTimeConfig {
* <li>Parameters including double-quotes must be wrapped into single-quotes</li>
* </ul>
*/
@ConfigItem(defaultValueDocumentation = "import.redis in DEV, TEST ; no-file otherwise")
@ConvertWith(TrimmedStringConverter.class)
public Optional<List<String>> loadScript;
@ConfigDocDefault("import.redis in DEV, TEST ; no-file otherwise")
@WithConverter(TrimmedStringConverter.class)
Optional<List<String>> loadScript();

/**
* When using {@code redisLoadScript}, indicates if the Redis database must be flushed (erased) before importing.
*/
@ConfigItem(defaultValue = "true")
public boolean flushBeforeLoad;
@WithDefault("true")
boolean flushBeforeLoad();

/**
* When using {@code redisLoadScript}, indicates if the import should only happen if the database is empty (no keys).
*/
@ConfigItem(defaultValue = "true")
public boolean loadOnlyIfEmpty;
@WithDefault("true")
boolean loadOnlyIfEmpty();

}
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,12 @@ public void init(
recorder.cleanup(shutdown);

// Handle data import
preloadRedisData(DEFAULT_CLIENT_NAME, buildTimeConfig.defaultRedisClient, applicationArchivesBuildItem,
preloadRedisData(DEFAULT_CLIENT_NAME, buildTimeConfig.defaultRedisClient(), applicationArchivesBuildItem,
launchMode.getLaunchMode(),
nativeImageResources, hotDeploymentWatchedFiles, recorder);

if (buildTimeConfig.namedRedisClients != null) {
for (Map.Entry<String, RedisClientBuildTimeConfig> entry : buildTimeConfig.namedRedisClients.entrySet()) {
if (buildTimeConfig.namedRedisClients() != null) {
for (Map.Entry<String, RedisClientBuildTimeConfig> entry : buildTimeConfig.namedRedisClients().entrySet()) {
preloadRedisData(entry.getKey(), entry.getValue(), applicationArchivesBuildItem, launchMode.getLaunchMode(),
nativeImageResources, hotDeploymentWatchedFiles, recorder);
}
Expand All @@ -197,10 +197,10 @@ public void init(
static Set<String> configuredClientNames(RedisBuildTimeConfig buildTimeConfig, Config config) {
Set<String> names = new HashSet<>();
// redis client names from dev services
if (buildTimeConfig.defaultDevService.devservices.enabled) {
if (buildTimeConfig.defaultDevService().devservices().enabled()) {
names.add(DEFAULT_CLIENT_NAME);
}
names.addAll(buildTimeConfig.additionalDevServices.keySet());
names.addAll(buildTimeConfig.additionalDevServices().keySet());
// redis client names declared in config
for (String propertyName : config.getPropertyNames()) {
if (propertyName.equals("quarkus.redis.hosts")) {
Expand Down Expand Up @@ -255,12 +255,12 @@ private void preloadRedisData(String name, RedisClientBuildTimeConfig clientConf
if (loadScriptPath != null && !Files.isDirectory(loadScriptPath)) {
// enlist resource if present
nativeImageResources.produce(new NativeImageResourceBuildItem(importFile));
} else if (clientConfig != null && clientConfig.loadScript.isPresent()) {
} else if (clientConfig != null && clientConfig.loadScript().isPresent()) {
//raise exception if explicit file is not present (i.e. not the default)
throw new ConfigurationException(
"Unable to find file referenced in '"
+ RedisConfig.propertyKey(name, "redis-load-script") + "="
+ String.join(", ", clientConfig.loadScript.get())
+ String.join(", ", clientConfig.loadScript().get())
+ "'. Remove property or add file to your path.");
}
// in dev mode we want to make sure that we watch for changes to file even if it doesn't currently exist
Expand All @@ -274,7 +274,7 @@ private void preloadRedisData(String name, RedisClientBuildTimeConfig clientConf

if (!paths.isEmpty()) {
if (clientConfig != null) {
recorder.preload(name, paths, clientConfig.flushBeforeLoad, clientConfig.loadOnlyIfEmpty);
recorder.preload(name, paths, clientConfig.flushBeforeLoad(), clientConfig.loadOnlyIfEmpty());
} else {
recorder.preload(name, paths, true, true);
}
Expand All @@ -285,7 +285,7 @@ private void preloadRedisData(String name, RedisClientBuildTimeConfig clientConf
@BuildStep
HealthBuildItem addHealthCheck(RedisBuildTimeConfig buildTimeConfig) {
return new HealthBuildItem("io.quarkus.redis.runtime.client.health.RedisHealthCheck",
buildTimeConfig.healthEnabled);
buildTimeConfig.healthEnabled());
}

public static final String NO_REDIS_SCRIPT_FILE = "no-file";
Expand All @@ -294,7 +294,7 @@ private static List<String> getRedisLoadScript(RedisClientBuildTimeConfig config
if (config == null) {
return List.of("import.redis");
}
var scripts = config.loadScript;
var scripts = config.loadScript();
if (scripts.isPresent()) {
return scripts.get().stream()
.filter(s -> !NO_REDIS_SCRIPT_FILE.equalsIgnoreCase(s))
Expand Down
Loading

0 comments on commit edda14a

Please sign in to comment.