io.quarkus.redis.runtime.client.RedisClientRecorder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of quarkus-redis-client Show documentation
Show all versions of quarkus-redis-client Show documentation
Connect to Redis in either imperative or reactive style
package io.quarkus.redis.runtime.client;
import static io.quarkus.redis.runtime.client.config.RedisConfig.DEFAULT_CLIENT_NAME;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.spi.CDI;
import io.quarkus.redis.client.RedisClient;
import io.quarkus.redis.client.reactive.ReactiveRedisClient;
import io.quarkus.redis.datasource.ReactiveRedisDataSource;
import io.quarkus.redis.datasource.RedisDataSource;
import io.quarkus.redis.datasource.codecs.Codec;
import io.quarkus.redis.datasource.codecs.Codecs;
import io.quarkus.redis.runtime.client.config.RedisClientConfig;
import io.quarkus.redis.runtime.client.config.RedisConfig;
import io.quarkus.redis.runtime.datasource.BlockingRedisDataSourceImpl;
import io.quarkus.redis.runtime.datasource.ReactiveRedisDataSourceImpl;
import io.quarkus.runtime.RuntimeValue;
import io.quarkus.runtime.ShutdownContext;
import io.quarkus.runtime.annotations.Recorder;
import io.quarkus.runtime.configuration.ConfigurationException;
import io.vertx.mutiny.core.Vertx;
import io.vertx.mutiny.redis.client.Command;
import io.vertx.mutiny.redis.client.Redis;
import io.vertx.mutiny.redis.client.RedisAPI;
import io.vertx.mutiny.redis.client.Request;
@Recorder
public class RedisClientRecorder {
// Split client and DS recorders
private final RedisConfig config;
private static final Map clients = new HashMap<>();
private static final Map dataSources = new HashMap<>();
private Vertx vertx;
private ObservableRedisMetrics metrics;
public RedisClientRecorder(RedisConfig rc) {
this.config = rc;
}
public void initialize(RuntimeValue vertx, Set names) {
Instance instance = CDI.current().select(ObservableRedisMetrics.class);
if (instance.isResolvable()) {
this.metrics = instance.get();
} else {
this.metrics = null;
}
this.vertx = Vertx.newInstance(vertx.getValue());
_registerCodecs();
_initialize(vertx.getValue(), names);
}
private static void _registerCodecs() {
Instance codecs = CDI.current().select(Codec.class);
Codecs.register(codecs.stream());
}
public void _initialize(io.vertx.core.Vertx vertx, Set names) {
for (String name : names) {
// Search if we have an associated config:
// - if default -> Default
// - if named -> Look for that config
// - if not found -> ConfigurationException
Optional maybe = getConfigForName(config, name);
if (!RedisConfig.isDefaultClient(name)) {
RedisClientConfig actualConfig = maybe
.orElseThrow(new Supplier() {
@Override
public ConfigurationException get() {
return new ConfigurationException("The application contains a " +
"@RedisClientName(\"" + name
+ "\"), but the application configuration does not configure this " +
"redis client configuration with that name. " +
"You must at least configure `quarkus.redis." + name + ".hosts`.");
}
});
clients.computeIfAbsent(name,
x -> new RedisClientAndApi(name, VertxRedisClientFactory.create(name, vertx, actualConfig), metrics));
} else if (DEFAULT_CLIENT_NAME.equalsIgnoreCase(name) && maybe.isPresent()) {
clients.computeIfAbsent(name,
x -> new RedisClientAndApi(name,
VertxRedisClientFactory.create(DEFAULT_CLIENT_NAME, vertx, maybe.get()), metrics));
}
// Do not throw an error. We would need to check if the default redis client is used.
}
}
static Optional getConfigForName(RedisConfig cfg, String name) {
if (RedisConfig.isDefaultClient(name)) {
return Optional.ofNullable(cfg.defaultRedisClient());
}
for (Map.Entry entry : cfg.namedRedisClients().entrySet()) {
if (entry.getKey().equalsIgnoreCase(name)) {
return Optional.of(entry.getValue());
}
}
return Optional.empty();
}
public Supplier getRedisClient(String name) {
return new Supplier() {
@Override
public Redis get() {
return clients.get(name).redis;
}
};
}
public Supplier getBareRedisClient(String name) {
return new Supplier() {
@Override
public io.vertx.redis.client.Redis get() {
return clients.get(name).observable;
}
};
}
public Supplier getRedisAPI(String name) {
return new Supplier() {
@Override
public RedisAPI get() {
return clients.get(name).api;
}
};
}
public Supplier getBareRedisAPI(String name) {
return new Supplier() {
@Override
public io.vertx.redis.client.RedisAPI get() {
return clients.get(name).api.getDelegate();
}
};
}
public Supplier getReactiveDataSource(String name) {
return new Supplier() {
@Override
public ReactiveRedisDataSource get() {
return dataSources.computeIfAbsent(name, k -> {
RedisClientAndApi redisClientAndApi = clients.get(name);
Redis redis = redisClientAndApi.redis;
RedisAPI api = redisClientAndApi.api;
return new ReactiveRedisDataSourceImpl(vertx, redis, api);
});
}
};
}
public Supplier getBlockingDataSource(String name) {
return new Supplier() {
@Override
public RedisDataSource get() {
Duration timeout = RedisClientRecorder.this.getTimeoutForClient(name);
return new BlockingRedisDataSourceImpl(
(ReactiveRedisDataSourceImpl) RedisClientRecorder.this.getReactiveDataSource(name).get(), timeout);
}
};
}
// Legacy client
public Supplier getLegacyRedisClient(String name) {
return new Supplier() {
@Override
public RedisClient get() {
Duration timeout = getTimeoutForClient(name);
return new RedisClientImpl(
RedisClientRecorder.this.getRedisClient(name).get(),
RedisClientRecorder.this.getRedisAPI(name).get(),
timeout);
}
};
}
private Duration getTimeoutForClient(String name) {
Duration timeout;
if (RedisConfig.isDefaultClient(name)) {
timeout = config.defaultRedisClient().timeout();
} else {
timeout = config.namedRedisClients().get(name).timeout();
}
return timeout;
}
public Supplier getLegacyReactiveRedisClient(String name) {
return new Supplier() {
@Override
public ReactiveRedisClient get() {
return new ReactiveRedisClientImpl(RedisClientRecorder.this.getRedisClient(name).get(),
RedisClientRecorder.this.getRedisAPI(name).get());
}
};
}
public void cleanup(ShutdownContext context) {
context.addShutdownTask(new Runnable() {
@Override
public void run() {
for (RedisClientAndApi value : clients.values()) {
value.redis.close();
}
clients.clear();
dataSources.clear();
}
});
}
public void preload(String name, List loadScriptPaths, boolean redisFlushBeforeLoad, boolean redisLoadOnlyIfEmpty) {
var tuple = clients.get(name);
if (tuple == null) {
throw new IllegalArgumentException("Unable import data into Redis - cannot find the Redis client " + name
+ ", available clients are: " + clients.keySet());
}
if (redisFlushBeforeLoad) {
tuple.redis.send(Request.cmd(Command.FLUSHALL)).await().indefinitely();
} else if (redisLoadOnlyIfEmpty) {
var list = tuple.redis.send(Request.cmd(Command.KEYS).arg("*")).await().indefinitely();
if (list.size() != 0) {
RedisDataLoader.LOGGER.debugf(
"Skipping the Redis data loading because the database is not empty: %d keys found", list.size());
return;
}
}
for (String path : loadScriptPaths) {
RedisDataLoader.load(vertx, tuple.redis, path);
}
}
private static class RedisClientAndApi {
private final Redis redis;
private final RedisAPI api;
private final ObservableRedis observable;
private RedisClientAndApi(String name, io.vertx.redis.client.Redis redis, ObservableRedisMetrics metrics) {
this.observable = new ObservableRedis(redis, name, metrics);
this.redis = Redis.newInstance(this.observable);
this.api = RedisAPI.api(this.redis);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy