Skip to content

Commit

Permalink
feat(redis): check Reactive Client for healthcheck
Browse files Browse the repository at this point in the history
Follows up #12781 (comment)
  • Loading branch information
machi1990 committed Oct 24, 2020
1 parent c7e5440 commit 3c43871
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import io.quarkus.redis.client.RedisClient;
import io.quarkus.redis.client.reactive.ReactiveRedisClient;
import io.quarkus.redis.client.runtime.RedisConfig.RedisConfiguration;
import io.vertx.core.Vertx;
import io.vertx.redis.client.Redis;
import io.vertx.redis.client.RedisAPI;
Expand All @@ -17,10 +18,10 @@ class RedisAPIProducer {
private static Map<String, RedisAPIContainer> REDIS_APIS = new ConcurrentHashMap<>();

private final Vertx vertx;
private final RedisConfig redisRuntimeConfig;
private final RedisConfig redisConfig;

public RedisAPIProducer(RedisConfig redisConfig, Vertx vertx) {
this.redisRuntimeConfig = redisConfig;
this.redisConfig = redisConfig;
this.vertx = vertx;
}

Expand All @@ -29,11 +30,12 @@ public RedisAPIContainer getRedisAPIContainer(String name) {
@Override
public RedisAPIContainer apply(String s) {
long timeout = 10;
RedisConfig.RedisConfiguration redisConfig = RedisClientUtil.getConfiguration(redisRuntimeConfig, name);
if (redisConfig.timeout.isPresent()) {
timeout = redisConfig.timeout.get().getSeconds();
RedisConfiguration redisConfiguration = RedisClientUtil.getConfiguration(RedisAPIProducer.this.redisConfig,
name);
if (redisConfiguration.timeout.isPresent()) {
timeout = redisConfiguration.timeout.get().getSeconds();
}
RedisOptions options = RedisClientUtil.buildOptions(redisConfig);
RedisOptions options = RedisClientUtil.buildOptions(redisConfiguration);
Redis redis = Redis.createClient(vertx, options);
RedisAPI redisAPI = RedisAPI.api(redis);
MutinyRedis mutinyRedis = new MutinyRedis(redis);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import static io.quarkus.redis.client.runtime.RedisClientUtil.DEFAULT_CLIENT;

import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.spi.Bean;

import org.eclipse.microprofile.health.HealthCheck;
Expand All @@ -17,41 +18,87 @@
import org.eclipse.microprofile.health.Readiness;

import io.quarkus.arc.Arc;
import io.quarkus.arc.InstanceHandle;
import io.quarkus.redis.client.RedisClient;
import io.quarkus.redis.client.RedisClientName;
import io.quarkus.redis.client.reactive.ReactiveRedisClient;
import io.quarkus.redis.client.runtime.RedisClientUtil;
import io.quarkus.redis.client.runtime.RedisConfig;
import io.quarkus.redis.client.runtime.RedisConfig.RedisConfiguration;
import io.vertx.redis.client.Response;

@Readiness
@ApplicationScoped
class RedisHealthCheck implements HealthCheck {
private Map<String, RedisClient> clients = new HashMap<>();
private final Map<String, RedisClient> clients = new HashMap<>();
private final Map<String, ReactiveRedisClient> reactiveClients = new HashMap<>();
private final RedisConfig redisConfig;

public RedisHealthCheck(RedisConfig redisConfig) {
this.redisConfig = redisConfig;
}

@PostConstruct
protected void init() {
Set<Bean<?>> beans = Arc.container().beanManager().getBeans(RedisClient.class);
for (Bean<?> bean : beans) {
if (bean.getName() == null) {
// this is the default redis client: retrieve it by type
RedisClient defaultClient = Arc.container().instance(RedisClient.class).get();
clients.put(DEFAULT_CLIENT, defaultClient);
} else {
RedisClient client = (RedisClient) Arc.container().instance(bean.getName()).get();
clients.put(bean.getName(), client);
for (InstanceHandle<RedisClient> handle : Arc.container().select(RedisClient.class, Any.Literal.INSTANCE).handles()) {
String clientName = getClientName(handle.getBean());
clients.put(clientName == null ? DEFAULT_CLIENT : clientName, handle.get());
}

for (InstanceHandle<ReactiveRedisClient> handle : Arc.container()
.select(ReactiveRedisClient.class, Any.Literal.INSTANCE).handles()) {
String clientName = getClientName(handle.getBean());
reactiveClients.put(clientName == null ? DEFAULT_CLIENT : clientName, handle.get());
}
}

private String getClientName(Bean bean) {
for (Object qualifier : bean.getQualifiers()) {
if (qualifier instanceof RedisClientName) {
return ((RedisClientName) qualifier).value();
}
}
return null;
}

@Override
public HealthCheckResponse call() {
HealthCheckResponseBuilder builder = HealthCheckResponse.named("Redis connection health check").up();
for (Map.Entry<String, RedisClient> client : clients.entrySet()) {
boolean isDefault = DEFAULT_CLIENT.equals(client.getKey());
RedisClient redisClient = client.getValue();
try {
boolean isDefault = DEFAULT_CLIENT.equals(client.getKey());
RedisClient redisClient = client.getValue();
String redisClientName = isDefault ? "default" : client.getKey();
Response response = redisClient.ping(Collections.emptyList());
builder.up().withData(redisClientName, response.toString());
} catch (Exception e) {
return builder.down().withData("reason", e.getMessage()).build();
return builder.down().withData("reason", "client [" + client.getKey() + "]: " + e.getMessage()).build();
}
}

for (Map.Entry<String, ReactiveRedisClient> client : reactiveClients.entrySet()) {

// Ignore named ReactiveRedisClient that have a blocking RedisClient since they have already been checked as part of blocking clients
if (clients.containsKey(client.getKey())) {
continue;
}

try {
boolean isDefault = DEFAULT_CLIENT.equals(client.getKey());
ReactiveRedisClient redisClient = client.getValue();
RedisConfiguration redisConfig = RedisClientUtil.getConfiguration(this.redisConfig,
isDefault ? DEFAULT_CLIENT : client.getKey());
long timeout = 10;
if (redisConfig.timeout.isPresent()) {
timeout = redisConfig.timeout.get().getSeconds();
}
String redisClientName = isDefault ? "default" : client.getKey();
io.vertx.mutiny.redis.client.Response response = redisClient.ping(Collections.emptyList()).await()
.atMost(Duration.ofSeconds(timeout));
builder.up().withData(redisClientName, response.toString());
} catch (Exception e) {
return builder.down().withData("reason", "client [" + client.getKey() + "]: " + e.getMessage())
.build();
}
}
return builder.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class RedisWithNamedClientResource {
RedisClient redisClient;

@Inject
@RedisClientName("named-client")
@RedisClientName("named-reactive-client")
ReactiveRedisClient reactiveRedisClient;

// synchronous
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
quarkus.redis.hosts=redis://localhost:6379/0
quarkus.redis.named-client.hosts=redis://localhost:6379/1
quarkus.redis.parameter-injection.hosts=redis://localhost:6379/2
quarkus.redis.named-reactive-client.hosts=redis://localhost:6379/1
quarkus.native.additional-build-args=-H:+TraceClassInitialization
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasKey;

import org.junit.jupiter.api.Test;

Expand All @@ -19,6 +20,9 @@ public void testHealthCheck() {
.header("Content-Type", containsString("charset=UTF-8"))
.body("status", is("UP"),
"checks.status", containsInAnyOrder("UP"),
"checks.data", containsInAnyOrder(hasKey("default")),
"checks.data", containsInAnyOrder(hasKey("named-client")),
"checks.data", containsInAnyOrder(hasKey("named-reactive-client")),
"checks.name", containsInAnyOrder("Redis connection health check"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
import io.quarkus.test.junit.NativeImageTest;

@NativeImageTest
class QuarkusRedisWithNamedClientIT extends QuarkusRedisWithNamedTest {
class QuarkusRedisWithNamedClientIT extends QuarkusRedisWithNamedClientTest {

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import io.restassured.RestAssured;

@QuarkusTest
class QuarkusRedisWithNamedTest {
class QuarkusRedisWithNamedClientTest {
static final String SYNC_KEY = "named-sync-key";
static final String SYNC_VALUE = "named-sync-value";

Expand Down

0 comments on commit 3c43871

Please sign in to comment.