diff --git a/.github/boring-cyborg.yml b/.github/boring-cyborg.yml
index d34133e16271d7..187e93f1a513b0 100644
--- a/.github/boring-cyborg.yml
+++ b/.github/boring-cyborg.yml
@@ -280,9 +280,11 @@ labelPRBasedOnFilePath:
- extensions/vertx/**/*
- extensions/vertx-core/**/*
- extensions/vertx-graphql/**/*
+ - extensions/vertx-redis/**/*
- extensions/vertx-http/**/*
- extensions/vertx-keycloak/**/*
- extensions/vertx-web/**/*
- integration-tests/vertx/**/*
- integration-tests/vertx-graphql/**/*
+ - integration-tests/vertx-redis/**/*
- integration-tests/vertx-http/**/*
diff --git a/.github/workflows/ci-actions.yml b/.github/workflows/ci-actions.yml
index c95c4b8a626bbe..abcf1ef097a76f 100644
--- a/.github/workflows/ci-actions.yml
+++ b/.github/workflows/ci-actions.yml
@@ -34,8 +34,8 @@ on:
env:
# Workaround testsuite locale issue
LANG: en_US.UTF-8
- NATIVE_TEST_MAVEN_OPTS: "-B --settings .github/mvn-settings.xml --fail-at-end -Dquarkus.native.container-build=true -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-native-image:19.3.1-java11 -Dtest-postgresql -Dtest-elasticsearch -Dtest-keycloak -Dtest-amazon-services -Dtest-mysql -Dtest-mariadb -Dmariadb.url='jdbc:mariadb://localhost:3308/hibernate_orm_test' -Dtest-mssql -Dtest-vault -Dtest-neo4j -Dtest-kafka -Dnative-image.xmx=5g -Dnative -Dformat.skip install"
- JVM_TEST_MAVEN_OPTS: "-e -B --settings .github/mvn-settings.xml -Dtest-postgresql -Dtest-elasticsearch -Dtest-mysql -Dtest-mariadb -Dmariadb.url='jdbc:mariadb://localhost:3308/hibernate_orm_test' -Dtest-mssql -Dtest-amazon-services -Dtest-vault -Dtest-neo4j -Dtest-kafka -Dtest-keycloak -Dformat.skip"
+ NATIVE_TEST_MAVEN_OPTS: "-B --settings .github/mvn-settings.xml --fail-at-end -Dquarkus.native.container-build=true -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-native-image:19.3.1-java11 -Dtest-postgresql -Dtest-elasticsearch -Dtest-keycloak -Dtest-amazon-services -Dtest-mysql -Dtest-redis -Dtest-mariadb -Dmariadb.url='jdbc:mariadb://localhost:3308/hibernate_orm_test' -Dtest-mssql -Dtest-vault -Dtest-neo4j -Dtest-kafka -Dnative-image.xmx=5g -Dnative -Dformat.skip install"
+ JVM_TEST_MAVEN_OPTS: "-e -B --settings .github/mvn-settings.xml -Dtest-postgresql -Dtest-elasticsearch -Dtest-mysql -Dtest-mariadb -Dmariadb.url='jdbc:mariadb://localhost:3308/hibernate_orm_test' -Dtest-mssql -Dtest-amazon-services -Dtest-vault -Dtest-neo4j -Dtest-kafka -Dtest-keycloak -Dtest-redis -Dformat.skip"
DB_USER: hibernate_orm_test
DB_PASSWORD: hibernate_orm_test
DB_NAME: hibernate_orm_test
@@ -70,7 +70,7 @@ jobs:
- name: Compute cache restore key
# Always recompute on a push so that the maven repo doesnt grow indefinitely with old versions
run: |
- if ${{ github.event_name == 'pull_request' }}; then echo "::set-env name=COMPUTED_RESTORE_KEY::q2maven-"; fi
+ if ${{ github.event_name == 'pull_request' }}; then echo "::set-env name=COMPUTED_RESTORE_KEY::q2maven-"; fi
- name: Cache Maven Repository
id: cache-maven
uses: n1hility/cache@v2
@@ -158,7 +158,7 @@ jobs:
image: neo4j/neo4j-experimental:4.0.0-rc01
env:
NEO4J_AUTH: neo4j/secret
- NEO4J_dbms_memory_pagecache_size: 10M
+ NEO4J_dbms_memory_pagecache_size: 10M
NEO4J_dbms_memory_heap_initial__size: 10M
ports:
- 127.0.0.1:7687:7687
@@ -172,7 +172,10 @@ jobs:
- 127.0.0.1:8008:4572
- 127.0.0.1:8009:4575
- 127.0.0.1:8010:4576
-
+ redis:
+ image: redis:5.0.8-alpine
+ ports:
+ - 127.0.0.1:6379:6379
steps:
- name: Start mysql
shell: bash
@@ -209,7 +212,7 @@ jobs:
- name: Prepare failure archive (if maven failed)
if: failure()
shell: bash
- run: find . -name '*-reports' -type d | tar -czvf test-reports.tgz -T -
+ run: find . -name '*-reports' -type d | tar -czvf test-reports.tgz -T -
- name: Upload failure Archive (if maven failed)
uses: actions/upload-artifact@v1
if: failure()
@@ -224,7 +227,7 @@ jobs:
timeout-minutes: 120
env:
MAVEN_OPTS: -Xmx1408m
-
+
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
@@ -275,7 +278,7 @@ jobs:
image: neo4j/neo4j-experimental:4.0.0-rc01
env:
NEO4J_AUTH: neo4j/secret
- NEO4J_dbms_memory_pagecache_size: 10M
+ NEO4J_dbms_memory_pagecache_size: 10M
NEO4J_dbms_memory_heap_initial__size: 10M
ports:
- 7687:7687
@@ -319,14 +322,14 @@ jobs:
- name: Prepare failure archive (if maven failed)
if: failure()
shell: bash
- run: find . -name '*-reports' -type d | tar -czvf test-reports.tgz -T -
+ run: find . -name '*-reports' -type d | tar -czvf test-reports.tgz -T -
- name: Upload failure Archive (if maven failed)
uses: actions/upload-artifact@v1
if: failure()
with:
name: test-reports-tcks
path: 'test-reports.tgz'
-
+
native-tests:
name: Native Tests - ${{matrix.category}}
needs: build-jdk11
@@ -373,10 +376,12 @@ jobs:
panache-rest-hibernate-orm
- category: Data4
neo4j: "true"
- timeout: 30
+ redis: "true"
+ timeout: 45
test-modules: >
mongodb-client
mongodb-panache
+ vertx-redis
neo4j
- category: Data5
timeout: 30
@@ -492,9 +497,9 @@ jobs:
# These should be services, but services do not (yet) allow conditional execution
- name: Postgres Service
run: |
- docker run --rm --publish 5432:5432 --name build-postgres \
- -e POSTGRES_USER=$DB_USER -e POSTGRES_PASSWORD=$DB_PASSWORD -e POSTGRES_DB=$DB_NAME \
- -d postgres:10.5
+ docker run --rm --publish 5432:5432 --name build-postgres \
+ -e POSTGRES_USER=$DB_USER -e POSTGRES_PASSWORD=$DB_PASSWORD -e POSTGRES_DB=$DB_NAME \
+ -d postgres:10.5
if: matrix.postgres
- name: MySQL Service
run: |
@@ -526,6 +531,9 @@ jobs:
-e NEO4J_AUTH=neo4j/secret -e NEO4J_dbms_memory_pagecache_size=10M -e NEO4J_dbms_memory_heap_initial__size=10M \
-d neo4j/neo4j-experimental:4.0.0-rc01
if: matrix.neo4j
+ - name: Redis Service
+ run: docker run --rm --publish 6379:6379 --name build-redis -d redis:5.0.8-alpine
+ if: matrix.redis
- name: Keycloak Service
run: |
docker run --rm --publish 8180:8080 --publish 8543:8443 --name build-keycloak \
@@ -552,7 +560,7 @@ jobs:
shell: bash
run: tar -xzvf maven-repo.tgz -C ~
- name: Build with Maven
- env:
+ env:
TEST_MODULES: ${{matrix.test-modules}}
CATEGORY: ${{matrix.category}}
run: |
@@ -569,7 +577,7 @@ jobs:
- name: Prepare failure archive (if maven failed)
if: failure()
shell: bash
- run: find . -name '*-reports' -type d | tar -czvf test-reports.tgz -T -
+ run: find . -name '*-reports' -type d | tar -czvf test-reports.tgz -T -
- name: Upload failure Archive (if maven failed)
uses: actions/upload-artifact@v1
if: failure()
diff --git a/bom/deployment/pom.xml b/bom/deployment/pom.xml
index ca6883a398aa42..406521bd9b7f93 100644
--- a/bom/deployment/pom.xml
+++ b/bom/deployment/pom.xml
@@ -753,6 +753,11 @@
quarkus-jsch-deployment
${project.version}
+
+ io.quarkus
+ quarkus-vertx-redis-deployment
+ ${project.version}
+
io.quarkus
quarkus-vault-deployment
diff --git a/bom/runtime/pom.xml b/bom/runtime/pom.xml
index 01028bd349325f..aca500f0f5e10e 100644
--- a/bom/runtime/pom.xml
+++ b/bom/runtime/pom.xml
@@ -2586,6 +2586,16 @@
smallrye-mutiny-vertx-mail-client
${mutiny-client.version}
+
+ io.smallrye.reactive
+ smallrye-mutiny-vertx-redis-client
+ ${mutiny-client.version}
+
+
+ io.smallrye.reactive
+ smallrye-axle-redis-client
+ ${axle-client.version}
+
io.vertx
vertx-rx-java2
@@ -3229,6 +3239,12 @@
${project.version}
+
+ io.quarkus
+ quarkus-vertx-redis
+ ${project.version}
+
+
io.quarkus.qute
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/FeatureBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/FeatureBuildItem.java
index 4e701efa50068c..410cc718ead1b8 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/FeatureBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/FeatureBuildItem.java
@@ -110,6 +110,7 @@ public final class FeatureBuildItem extends MultiBuildItem {
public static final String VERTX = "vertx";
public static final String VERTX_WEB = "vertx-web";
public static final String VERTX_GRAPHQL = "vertx-graphql";
+ public static final String VERTX_REDIS = "vertx-redis";
private final String info;
diff --git a/docs/src/main/asciidoc/index.adoc b/docs/src/main/asciidoc/index.adoc
index c51934534119ae..493608f30149cd 100644
--- a/docs/src/main/asciidoc/index.adoc
+++ b/docs/src/main/asciidoc/index.adoc
@@ -62,6 +62,7 @@ include::quarkus-intro.adoc[tag=intro]
* link:camel.html[Apache Camel]
* link:command-mode-reference.html[Command Mode Applications]
* link:grpc.html[Using gRPC]
+* link:redis.html[Connecting to Redis]
* link:faq.html[FAQs]
diff --git a/docs/src/main/asciidoc/redis.adoc b/docs/src/main/asciidoc/redis.adoc
new file mode 100644
index 00000000000000..db0c5bfcc0f680
--- /dev/null
+++ b/docs/src/main/asciidoc/redis.adoc
@@ -0,0 +1,536 @@
+////
+This guide is maintained in the main Quarkus repository
+and pull requests should be submitted there:
+https://github.com/quarkusio/quarkus/tree/master/docs/src/main/asciidoc
+////
+= Quarkus - Using Vertx Redis extension
+include::./attributes.adoc[]
+
+This guide demonstrates how your Quarkus application can use the Redis extension.
+
+[NOTE]
+====
+This extension is considered `preview`.
+API or configuration properties might change as the extension matures.
+Feedback is welcome on our https://groups.google.com/d/forum/quarkus-dev[mailing list] or as issues in our https://github.com/quarkusio/quarkus/issues[GitHub issue tracker].
+====
+
+== Prerequisites
+
+To complete this guide, you need:
+
+* less than 15 minutes
+* an IDE
+* JDK 1.8+ installed with `JAVA_HOME` configured appropriately
+* Apache Maven 3.5.3+
+* A running Redis server, or Docker Compose to start one
+* GraalVM installed if you want to run in native mode.
+
+== Architecture
+
+In this guide, we are going to expose a simple Rest API to increment numbers by using the https://redis.io/commands/incrby[`INCRBY`] command.
+Along the way, we'll see how to use other Redis commands like `GET`, `SET`, `DEL` and `KEYS`.
+
+== Solution
+
+We recommend that you follow the instructions in the next sections and create the application step by step.
+However, you can go right to the completed example.
+
+Clone the Git repository: `git clone {quickstarts-clone-url}`, or download an {quickstarts-archive-url}[archive].
+
+The solution is located in the `redis-quickstart` {quickstarts-tree-url}/redis-quickstart[directory].
+
+== Creating the Maven Project
+
+First, we need a new project. Create a new project with the following command:
+
+[source, subs=attributes+]
+----
+mvn io.quarkus:quarkus-maven-plugin:{quarkus-version}:create \
+ -DprojectGroupId=org.acme \
+ -DprojectArtifactId=redis-quickstart \
+ -Dextensions="vertx-redis, resteasy-jsonb, resteasy-mutiny"
+cd redis-quickstart
+----
+
+This command generates a Maven project, importing the Redis extension.
+
+== Starting the Redis server
+
+Then, we need to start a Redis instance (if you do not have one already) using the following command:
+
+[source, bash]
+----
+docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 --name redis_quarkus_test -p 6379:6379 redis:5.0.6
+----
+
+== Configuring Redis properties
+
+Once we have the Redis server running, we need to configure the Redis connection properties.
+This is done in the `application.properties` configuration file. Edit it to the following content:
+
+[source]
+----
+quarkus.redis.hosts=localhost:6379 <1>
+----
+
+1. Configure Redis hosts to connect to. Here we connect to the Redis server we started in the previous section
+
+== Creating the Increment POJO
+
+We are going to model our increments using the `Increment` POJO.
+Create the `src/main/java/org/acme/redis/Increment.java` file, with the following content:
+
+[source, java]
+----
+package org.acme.redis;
+
+public class Increment {
+ public String key; <1>
+ public int value; <2>
+
+ public Increment(String key, int value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public Increment() {
+ }
+}
+----
+
+1. The key that will be used as the Redis key
+2. The value held by the Redis key
+
+
+== Creating the Increment Service
+
+We are going to create an `IncrementService` class which will play the role of a Redis client.
+With this class, we'll be able to do the perform the `SET`, `GET` , `DELET`, `KEYS` and `INCRBY` Redis commands.
+
+Create the `src/main/java/org/acme/redis/IncrementService.java` file, with the following content:
+
+[source, java]
+----
+package org.acme.redis;
+
+import io.quarkus.vertx.redis.SyncRedisAPI;
+import io.smallrye.mutiny.Uni;
+
+import io.vertx.mutiny.redis.client.Response;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+@Singleton
+class IncrementService {
+
+ @Inject
+ SyncRedisAPI syncRedisAPI; <1>
+
+ @Inject
+ io.vertx.mutiny.redis.client.RedisAPI mutinyRedisAPI; <2>
+
+ @Inject
+ io.vertx.axle.redis.client.RedisAPI axleRedisAPI; <3>
+
+ CompletionStage del(String key) {
+ return axleRedisAPI.del(Arrays.asList(key))
+ .thenAccept(response -> {});
+ }
+
+ String get(String key) {
+ return syncRedisAPI.get(key).toString();
+ }
+
+ void set(String key, Integer value) {
+ syncRedisAPI.set(Arrays.asList(key, value.toString()));
+ }
+
+ void increment(String key, Integer incrementBy) {
+ syncRedisAPI.incrby(key, incrementBy.toString());
+ }
+
+ Uni> keys() {
+ return mutinyRedisAPI
+ .keys("*")
+ .map(response -> {
+ List result = new ArrayList<>();
+ for (Response r : response) {
+ result.add(r.toString());
+ }
+ return result;
+ });
+ }
+}
+----
+
+1. Inject the Redis synchronous client
+2. Inject the mutiny reactive redis client
+3. Inject the axle reactive redis client
+
+== Creating the Increment Resource
+
+Create the `src/main/java/org/acme/redis/IncrementResource.java` file, with the following content:
+
+[source, java]
+----
+package org.acme.redis;
+
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.Path;
+import javax.ws.rs.POST;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+
+import io.smallrye.mutiny.Uni;
+
+@Path("/increments")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class IncrementResource {
+
+ @Inject
+ IncrementService service;
+
+ @GET
+ public Uni> keys() {
+ return service.keys();
+ }
+
+ @POST
+ public Increment create(Increment increment) {
+ service.set(increment.key, increment.value);
+ return increment;
+ }
+
+ @GET
+ @Path("/{key}")
+ public Increment get(@PathParam("key") String key) {
+ return new Increment(key, Integer.valueOf(service.get(key)));
+ }
+
+ @PUT
+ @Path("/{key}")
+ public void increment(@PathParam("key") String key, Integer value) {
+ service.increment(key, value);
+ }
+
+ @DELETE
+ @Path("/{key}")
+ public CompletionStage delete(@PathParam("key") String key) {
+ return service.del(key);
+ }
+}
+----
+
+== Modifying the test class
+
+Edit the `src/test/java/org/acme/redis/IncrementResourceTest.java` file to the following content:
+
+[source, java]
+----
+package org.acme.redis;
+
+import static org.hamcrest.Matchers.is;
+
+import org.junit.jupiter.api.Test;
+
+import io.quarkus.test.junit.QuarkusTest;
+
+import static io.restassured.RestAssured.given;
+
+import io.restassured.http.ContentType;
+
+@QuarkusTest
+public class IncrementResourceTest {
+
+ @Test
+ public void testRedisOperations() {
+ // verify that we have nothing
+ given()
+ .accept(ContentType.JSON)
+ .when()
+ .get("/increments")
+ .then()
+ .statusCode(200)
+ .body("size()", is(0));
+
+ // create a first increment key with an initial value of 0
+ given()
+ .contentType(ContentType.JSON)
+ .accept(ContentType.JSON)
+ .body("{\"key\":\"first-key\",\"value\":0}")
+ .when()
+ .post("/increments")
+ .then()
+ .statusCode(200)
+ .body("key", is("first-key"))
+ .body("value", is(0));
+
+ // create a second increment key with an initial value of 10
+ given()
+ .contentType(ContentType.JSON)
+ .accept(ContentType.JSON)
+ .body("{\"key\":\"second-key\",\"value\":10}")
+ .when()
+ .post("/increments")
+ .then()
+ .statusCode(200)
+ .body("key", is("second-key"))
+ .body("value", is(10));
+
+ // increment first key by 1
+ given()
+ .contentType(ContentType.JSON)
+ .body("1")
+ .when()
+ .put("/increments/first-key")
+ .then()
+ .statusCode(204);
+
+ // verify that key has been incremented
+ given()
+ .accept(ContentType.JSON)
+ .when()
+ .get("/increments/first-key")
+ .then()
+ .statusCode(200)
+ .body("key", is("first-key"))
+ .body("value", is(1));
+
+ // increment second key by 1000
+ given()
+ .contentType(ContentType.JSON)
+ .body("1000")
+ .when()
+ .put("/increments/second-key")
+ .then()
+ .statusCode(204);
+
+ // verify that key has been incremented
+ given()
+ .accept(ContentType.JSON)
+ .when()
+ .get("/increments/second-key")
+ .then()
+ .statusCode(200)
+ .body("key", is("second-key"))
+ .body("value", is(1010));
+
+ // verify that we have two keys in registered
+ given()
+ .accept(ContentType.JSON)
+ .when()
+ .get("/increments")
+ .then()
+ .statusCode(200)
+ .body("size()", is(2));
+
+ // delete first key
+ given()
+ .accept(ContentType.JSON)
+ .when()
+ .delete("/increments/first-key")
+ .then()
+ .statusCode(204);
+
+ // verify that we have one key left after deletion
+ given()
+ .accept(ContentType.JSON)
+ .when()
+ .get("/increments")
+ .then()
+ .statusCode(200)
+ .body("size()", is(1));
+
+ // delete second key
+ given()
+ .accept(ContentType.JSON)
+ .when()
+ .delete("/increments/second-key")
+ .then()
+ .statusCode(204);
+
+ // verify that there is no key left
+ given()
+ .accept(ContentType.JSON)
+ .when()
+ .get("/increments")
+ .then()
+ .statusCode(200)
+ .body("size()", is(0));
+ }
+}
+----
+
+== Get it running
+
+If you followed the instructions, you should have the Redis server running.
+Then, you just need to run the application using:
+
+[source, shell]
+----
+./mvnw compile quarkus:dev
+----
+
+Open another terminal and run the `curl http://localhost:8080/increments` command.
+
+== Interacting with the application
+As we have seen above, the API exposes five Rest endpoints.
+In this section we are going to see how to initialise an increment, see the list of current increments,
+incrementing a value given its key, retrieving the current value of an increment, and finally deleting
+a key.
+
+=== Creating a new increment
+
+[source, shell]
+----
+curl -X POST -H "Content-Type: application/json" -d '{"key":"first","value":10}' http://localhost:8080/increments <1>
+----
+
+1. We create the first increment, with the key `first` and an initial value of `10`.
+
+Running the above command should return the result below:
+
+[source, json]
+-----
+{
+ "key": "first",
+ "value": 10
+}
+-----
+
+=== See current increments keys
+
+To see the list of current increments keys, run the following command:
+
+[source, shell]
+----
+curl http://localhost:8080/increments
+----
+
+The above command should return `["first"]` indicating that we have only one increment thus far.
+
+=== Retrieve an new increment
+
+To retrieve an increment using its key, we will have to run the below command:
+
+[source, shell]
+----
+curl http://localhost:8080/increments/first <1>
+----
+
+1. Running this command, should return the following result:
+
+[source, json]
+----
+{
+ "key": "first",
+ "value": 10
+}
+----
+
+=== Increment a value given its key
+
+To increment a value, run the following command:
+
+[source, shell]
+----
+curl -X PUT -H "Content-Type: application/json" -d '27' http://localhost:8080/increments/first <1>
+----
+
+1. Increment the `first` value by 27.
+
+Now, running the command `curl http://localhost:8080/increments/first` should return the following result:
+
+[source, json]
+----
+{
+ "key": "first",
+ "value": 37 <1>
+}
+----
+
+1. We see that the value of the `first` key is now `37` which is exactly the result of `10 + 27`, quick maths.
+
+=== Deleting a key
+
+Use the command below, to delete an increment given its key.
+
+[source, shell]
+----
+curl -X DELETE http://localhost:8080/increments/first <1>
+----
+
+1. Delete the `first` increment.
+
+Now, running the command `curl http://localhost:8080/increments` should return an empty list `[]`
+
+== Packaging and run in JVM mode
+
+You can run the application as a conventional jar file.
+
+First, we will need to package it:
+
+[source, shell]
+----
+./mvnw package
+----
+
+NOTE: This command will start a Redis instance to execute the tests. Thus your Redis containers need to be stopped.
+
+Then run it:
+
+[source, shell]
+----
+java -jar ./target/redis-quickstart-1.0-SNAPSHOT-runner.jar
+----
+
+== Running Native
+
+You can also create a native executable from this application without making any
+source code changes. A native executable removes the dependency on the JVM:
+everything needed to run the application on the target platform is included in
+the executable, allowing the application to run with minimal resource overhead.
+
+Compiling a native executable takes a bit longer, as GraalVM performs additional
+steps to remove unnecessary codepaths. Use the `native` profile to compile a
+native executable:
+
+[source, shell]
+----
+./mvnw package -Pnative
+----
+
+Once the build is finished, you can run the executable with:
+
+[source, shell]
+----
+./target/redis-quickstart-1.0-SNAPSHOT-runner
+----
+
+== Connection Health Check
+
+If you are using the `quarkus-smallrye-health` extension, `quarkus-vertx-redis` will automatically add a readiness health check
+to validate the connection to the Redis server.
+
+So when you access the `/health/ready` endpoint of your application you will have information about the connection validation status.
+
+This behavior can be disabled by setting the `quarkus.redis.health.enabled` property to `false` in your `application.properties`.
+
+== Configuration Reference
+
+include::{generated-dir}/config/quarkus-vertx-redis.adoc[opts=optional, leveloffset=+1]
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 9b1457d27762f4..bf8f2d00095fde 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -74,6 +74,7 @@
reactive-mysql-client
mailer
grpc
+ vertx-redis
narayana-jta
diff --git a/extensions/vertx-redis/deployment/pom.xml b/extensions/vertx-redis/deployment/pom.xml
new file mode 100644
index 00000000000000..d14f04337d6f94
--- /dev/null
+++ b/extensions/vertx-redis/deployment/pom.xml
@@ -0,0 +1,56 @@
+
+
+ 4.0.0
+
+
+ io.quarkus
+ quarkus-vertx-redis-parent
+ 999-SNAPSHOT
+ ../
+
+
+ quarkus-vertx-redis-deployment
+
+ Quarkus - Vertx Redis - Deployment
+
+
+
+ io.quarkus
+ quarkus-vertx-deployment
+
+
+ io.quarkus
+ quarkus-vertx-redis
+
+
+ io.quarkus
+ quarkus-smallrye-health-spi
+
+
+ io.quarkus
+ quarkus-junit5-internal
+ test
+
+
+
+
+
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${project.version}
+
+
+
+
+
+
+
+
diff --git a/extensions/vertx-redis/deployment/src/main/java/io/quarkus/vertx/redis/deployment/RedisBuildTimeConfig.java b/extensions/vertx-redis/deployment/src/main/java/io/quarkus/vertx/redis/deployment/RedisBuildTimeConfig.java
new file mode 100644
index 00000000000000..89ea6a71764848
--- /dev/null
+++ b/extensions/vertx-redis/deployment/src/main/java/io/quarkus/vertx/redis/deployment/RedisBuildTimeConfig.java
@@ -0,0 +1,13 @@
+package io.quarkus.vertx.redis.deployment;
+
+import io.quarkus.runtime.annotations.ConfigItem;
+import io.quarkus.runtime.annotations.ConfigRoot;
+
+@ConfigRoot
+public class RedisBuildTimeConfig {
+ /**
+ * Whether or not an health check is published in case the smallrye-health extension is present.
+ */
+ @ConfigItem(name = "health.enabled", defaultValue = "true")
+ public boolean healthEnabled;
+}
diff --git a/extensions/vertx-redis/deployment/src/main/java/io/quarkus/vertx/redis/deployment/VertxRedisProcessor.java b/extensions/vertx-redis/deployment/src/main/java/io/quarkus/vertx/redis/deployment/VertxRedisProcessor.java
new file mode 100644
index 00000000000000..be218959962bc4
--- /dev/null
+++ b/extensions/vertx-redis/deployment/src/main/java/io/quarkus/vertx/redis/deployment/VertxRedisProcessor.java
@@ -0,0 +1,47 @@
+package io.quarkus.vertx.redis.deployment;
+
+import static io.quarkus.deployment.builditem.FeatureBuildItem.VERTX_REDIS;
+
+import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
+import io.quarkus.arc.deployment.BeanContainerBuildItem;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.annotations.ExecutionTime;
+import io.quarkus.deployment.annotations.Record;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
+import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem;
+import io.quarkus.vertx.deployment.VertxBuildItem;
+import io.quarkus.vertx.redis.runtime.RedisAPIsProducer;
+import io.quarkus.vertx.redis.runtime.RedisConfig;
+import io.quarkus.vertx.redis.runtime.VertxRedisRecorder;
+import io.vertx.redis.client.impl.types.BulkType;
+
+public class VertxRedisProcessor {
+
+ @BuildStep
+ FeatureBuildItem feature() {
+ return new FeatureBuildItem(VERTX_REDIS);
+ }
+
+ @BuildStep
+ AdditionalBeanBuildItem registerAPIsProducer() {
+ return AdditionalBeanBuildItem.unremovableOf(RedisAPIsProducer.class);
+ }
+
+ @BuildStep
+ HealthBuildItem addHealthCheck(RedisBuildTimeConfig buildTimeConfig) {
+ return new HealthBuildItem("io.quarkus.vertx.redis.health.RedisHealthCheck",
+ buildTimeConfig.healthEnabled, "redis");
+ }
+
+ @BuildStep
+ RuntimeInitializedClassBuildItem initializeBulkTypeDuringRuntime() {
+ return new RuntimeInitializedClassBuildItem(BulkType.class.getName());
+ }
+
+ @BuildStep
+ @Record(ExecutionTime.RUNTIME_INIT)
+ void build(VertxRedisRecorder recorder, VertxBuildItem vertx, BeanContainerBuildItem beanContainer, RedisConfig config) {
+ recorder.initialize(config, beanContainer.getValue());
+ }
+}
diff --git a/extensions/vertx-redis/deployment/src/test/java/io/quarkus/vertx/redis/deployment/MultipleHostAddressSuppliedForStandaloneClientTest.java b/extensions/vertx-redis/deployment/src/test/java/io/quarkus/vertx/redis/deployment/MultipleHostAddressSuppliedForStandaloneClientTest.java
new file mode 100644
index 00000000000000..617a0d2e038375
--- /dev/null
+++ b/extensions/vertx-redis/deployment/src/test/java/io/quarkus/vertx/redis/deployment/MultipleHostAddressSuppliedForStandaloneClientTest.java
@@ -0,0 +1,29 @@
+package io.quarkus.vertx.redis.deployment;
+
+import static org.junit.jupiter.api.Assertions.fail;
+
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.quarkus.runtime.configuration.ConfigurationException;
+import io.quarkus.test.QuarkusUnitTest;
+
+public class MultipleHostAddressSuppliedForStandaloneClientTest {
+
+ @RegisterExtension
+ static final QuarkusUnitTest test = new QuarkusUnitTest()
+ .setExpectedException(ConfigurationException.class)
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+ .addAsResource(new StringAsset(
+ "quarkus.redis.hosts=localhost:6379,localhost:6380" +
+ "\nquarkus.redis.client-type=standalone"),
+ "application.properties"));
+
+ @Test
+ public void shouldNotReachHere() {
+ fail("Should not react here as we are expecting a building failure since you cannot have multiple hosts in standalone mode.");
+ }
+}
diff --git a/extensions/vertx-redis/pom.xml b/extensions/vertx-redis/pom.xml
new file mode 100644
index 00000000000000..43fe8f2914648c
--- /dev/null
+++ b/extensions/vertx-redis/pom.xml
@@ -0,0 +1,25 @@
+
+
+ 4.0.0
+
+
+ quarkus-build-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../../build-parent/pom.xml
+
+
+ quarkus-vertx-redis-parent
+ pom
+
+ Quarkus - Vertx Redis
+
+
+ deployment
+ runtime
+
+
+
+
diff --git a/extensions/vertx-redis/runtime/pom.xml b/extensions/vertx-redis/runtime/pom.xml
new file mode 100644
index 00000000000000..96a8b96d112635
--- /dev/null
+++ b/extensions/vertx-redis/runtime/pom.xml
@@ -0,0 +1,69 @@
+
+
+ 4.0.0
+
+
+ io.quarkus
+ quarkus-vertx-redis-parent
+ 999-SNAPSHOT
+ ../
+
+
+ quarkus-vertx-redis
+
+ Quarkus - Vertx Redis - Runtime
+ Synchronous and Reactive Redis client
+
+
+ io.quarkus
+ quarkus-vertx
+
+
+ io.smallrye.reactive
+ smallrye-axle-redis-client
+
+
+ io.smallrye.reactive
+ smallrye-mutiny-vertx-redis-client
+
+
+
+ io.quarkus
+ quarkus-smallrye-health
+ true
+
+
+ io.quarkus
+ quarkus-junit5-internal
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+
+
+
+
+ io.quarkus
+ quarkus-bootstrap-maven-plugin
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${project.version}
+
+
+
+
+
+
+
diff --git a/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/SyncRedisAPI.java b/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/SyncRedisAPI.java
new file mode 100644
index 00000000000000..254b06364f06b2
--- /dev/null
+++ b/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/SyncRedisAPI.java
@@ -0,0 +1,417 @@
+package io.quarkus.vertx.redis;
+
+import java.util.List;
+
+import io.vertx.redis.client.Response;
+
+/**
+ * A synchronous RedisAPI offering blocking Redis commands.
+ * The commands have a default timeout of 10 seconds which can be configured
+ * via {@code quarkus.redis.timeout} configuration knob.
+ *
+ * For more information about how each individual command visit
+ * the Redis Commands Page
+ */
+public interface SyncRedisAPI {
+ void close();
+
+ Response append(String arg0, String arg1);
+
+ Response asking();
+
+ Response auth(String arg0);
+
+ Response bgrewriteaof();
+
+ Response bgsave(List args);
+
+ Response bitcount(List args);
+
+ Response bitfield(List args);
+
+ Response bitop(List args);
+
+ Response bitpos(List args);
+
+ Response blpop(List args);
+
+ Response brpop(List args);
+
+ Response brpoplpush(String arg0, String arg1, String arg2);
+
+ Response bzpopmax(List args);
+
+ Response bzpopmin(List args);
+
+ Response client(List args);
+
+ Response cluster(List args);
+
+ Response command();
+
+ Response config(List args);
+
+ Response dbsize();
+
+ Response debug(List args);
+
+ Response decr(String arg0);
+
+ Response decrby(String arg0, String arg1);
+
+ Response del(List args);
+
+ Response discard();
+
+ Response dump(String arg0);
+
+ Response echo(String arg0);
+
+ Response eval(List args);
+
+ Response evalsha(List args);
+
+ Response exec();
+
+ Response exists(List args);
+
+ Response expire(String arg0, String arg1);
+
+ Response expireat(String arg0, String arg1);
+
+ Response flushall(List args);
+
+ Response flushdb(List args);
+
+ Response geoadd(List args);
+
+ Response geodist(List args);
+
+ Response geohash(List args);
+
+ Response geopos(List args);
+
+ Response georadius(List args);
+
+ Response georadiusRo(List args);
+
+ Response georadiusbymember(List args);
+
+ Response georadiusbymemberRo(List args);
+
+ Response get(String arg0);
+
+ Response getbit(String arg0, String arg1);
+
+ Response getrange(String arg0, String arg1, String arg2);
+
+ Response getset(String arg0, String arg1);
+
+ Response hdel(List args);
+
+ Response hexists(String arg0, String arg1);
+
+ Response hget(String arg0, String arg1);
+
+ Response hgetall(String arg0);
+
+ Response hincrby(String arg0, String arg1, String arg2);
+
+ Response hincrbyfloat(String arg0, String arg1, String arg2);
+
+ Response hkeys(String arg0);
+
+ Response hlen(String arg0);
+
+ Response hmget(List args);
+
+ Response hmset(List args);
+
+ Response host(List args);
+
+ Response hscan(List args);
+
+ Response hset(List args);
+
+ Response hsetnx(String arg0, String arg1, String arg2);
+
+ Response hstrlen(String arg0, String arg1);
+
+ Response hvals(String arg0);
+
+ Response incr(String arg0);
+
+ Response incrby(String arg0, String arg1);
+
+ Response incrbyfloat(String arg0, String arg1);
+
+ Response info(List args);
+
+ Response keys(String arg0);
+
+ Response lastsave();
+
+ Response latency(List args);
+
+ Response lindex(String arg0, String arg1);
+
+ Response linsert(String arg0, String arg1, String arg2, String arg3);
+
+ Response llen(String arg0);
+
+ Response lolwut(List args);
+
+ Response lpop(String arg0);
+
+ Response lpush(List args);
+
+ Response lpushx(List args);
+
+ Response lrange(String arg0, String arg1, String arg2);
+
+ Response lrem(String arg0, String arg1, String arg2);
+
+ Response lset(String arg0, String arg1, String arg2);
+
+ Response ltrim(String arg0, String arg1, String arg2);
+
+ Response memory(List args);
+
+ Response mget(List args);
+
+ Response migrate(List args);
+
+ Response module(List args);
+
+ Response monitor();
+
+ Response move(String arg0, String arg1);
+
+ Response mset(List args);
+
+ Response msetnx(List args);
+
+ Response multi();
+
+ Response object(List args);
+
+ Response persist(String arg0);
+
+ Response pexpire(String arg0, String arg1);
+
+ Response pexpireat(String arg0, String arg1);
+
+ Response pfadd(List args);
+
+ Response pfcount(List args);
+
+ Response pfdebug(List args);
+
+ Response pfmerge(List args);
+
+ Response pfselftest();
+
+ Response ping(List args);
+
+ Response post(List args);
+
+ Response psetex(String arg0, String arg1, String arg2);
+
+ Response psubscribe(List args);
+
+ Response psync(String arg0, String arg1);
+
+ Response pttl(String arg0);
+
+ Response publish(String arg0, String arg1);
+
+ Response pubsub(List args);
+
+ Response punsubscribe(List args);
+
+ Response randomkey();
+
+ Response readonly();
+
+ Response readwrite();
+
+ Response rename(String arg0, String arg1);
+
+ Response renamenx(String arg0, String arg1);
+
+ Response replconf(List args);
+
+ Response replicaof(String arg0, String arg1);
+
+ Response restore(List args);
+
+ Response restoreAsking(List args);
+
+ Response role();
+
+ Response rpop(String arg0);
+
+ Response rpoplpush(String arg0, String arg1);
+
+ Response rpush(List args);
+
+ Response rpushx(List args);
+
+ Response sadd(List args);
+
+ Response save();
+
+ Response scan(List args);
+
+ Response scard(String arg0);
+
+ Response script(List args);
+
+ Response sdiff(List args);
+
+ Response sdiffstore(List args);
+
+ Response select(String arg0);
+
+ Response set(List args);
+
+ Response setbit(String arg0, String arg1, String arg2);
+
+ Response setex(String arg0, String arg1, String arg2);
+
+ Response setnx(String arg0, String arg1);
+
+ Response setrange(String arg0, String arg1, String arg2);
+
+ Response shutdown(List args);
+
+ Response sinter(List args);
+
+ Response sinterstore(List args);
+
+ Response sismember(String arg0, String arg1);
+
+ Response slaveof(String arg0, String arg1);
+
+ Response slowlog(List args);
+
+ Response smembers(String arg0);
+
+ Response smove(String arg0, String arg1, String arg2);
+
+ Response sort(List args);
+
+ Response spop(List args);
+
+ Response srandmember(List args);
+
+ Response srem(List args);
+
+ Response sscan(List args);
+
+ Response strlen(String arg0);
+
+ Response subscribe(List args);
+
+ Response substr(String arg0, String arg1, String arg2);
+
+ Response sunion(List args);
+
+ Response sunionstore(List args);
+
+ Response swapdb(String arg0, String arg1);
+
+ Response sync();
+
+ Response time();
+
+ Response touch(List args);
+
+ Response ttl(String arg0);
+
+ Response type(String arg0);
+
+ Response unlink(List args);
+
+ Response unsubscribe(List args);
+
+ Response unwatch();
+
+ Response wait(String arg0, String arg1);
+
+ Response watch(List args);
+
+ Response xack(List args);
+
+ Response xadd(List args);
+
+ Response xclaim(List args);
+
+ Response xdel(List args);
+
+ Response xgroup(List args);
+
+ Response xinfo(List args);
+
+ Response xlen(String arg0);
+
+ Response xpending(List args);
+
+ Response xrange(List args);
+
+ Response xread(List args);
+
+ Response xreadgroup(List args);
+
+ Response xrevrange(List args);
+
+ Response xsetid(String arg0, String arg1);
+
+ Response xtrim(List args);
+
+ Response zadd(List args);
+
+ Response zcard(String arg0);
+
+ Response zcount(String arg0, String arg1, String arg2);
+
+ Response zincrby(String arg0, String arg1, String arg2);
+
+ Response zinterstore(List args);
+
+ Response zlexcount(String arg0, String arg1, String arg2);
+
+ Response zpopmax(List args);
+
+ Response zpopmin(List args);
+
+ Response zrange(List args);
+
+ Response zrangebylex(List args);
+
+ Response zrangebyscore(List args);
+
+ Response zrank(String arg0, String arg1);
+
+ Response zrem(List args);
+
+ Response zremrangebylex(String arg0, String arg1, String arg2);
+
+ Response zremrangebyrank(String arg0, String arg1, String arg2);
+
+ Response zremrangebyscore(String arg0, String arg1, String arg2);
+
+ Response zrevrange(List args);
+
+ Response zrevrangebylex(List args);
+
+ Response zrevrangebyscore(List args);
+
+ Response zrevrank(String arg0, String arg1);
+
+ Response zscan(List args);
+
+ Response zscore(String arg0, String arg1);
+
+ Response zunionstore(List args);
+}
diff --git a/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/health/RedisHealthCheck.java b/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/health/RedisHealthCheck.java
new file mode 100644
index 00000000000000..ee839901b8e240
--- /dev/null
+++ b/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/health/RedisHealthCheck.java
@@ -0,0 +1,36 @@
+package io.quarkus.vertx.redis.health;
+
+import java.util.Collections;
+
+import javax.enterprise.context.ApplicationScoped;
+
+import org.eclipse.microprofile.health.HealthCheck;
+import org.eclipse.microprofile.health.HealthCheckResponse;
+import org.eclipse.microprofile.health.HealthCheckResponseBuilder;
+import org.eclipse.microprofile.health.Readiness;
+
+import io.quarkus.arc.Arc;
+import io.quarkus.arc.InstanceHandle;
+import io.quarkus.vertx.redis.SyncRedisAPI;
+
+@Readiness
+@ApplicationScoped
+class RedisHealthCheck implements HealthCheck {
+
+ @Override
+ public HealthCheckResponse call() {
+ HealthCheckResponseBuilder builder = HealthCheckResponse.named("Redis connection health check").up();
+
+ try (InstanceHandle instanceHandle = Arc.container().instance(SyncRedisAPI.class)) {
+ if (!instanceHandle.isAvailable()) {
+ builder.down();
+ } else {
+ SyncRedisAPI redisAPI = instanceHandle.get();
+ redisAPI.ping(Collections.emptyList());
+ }
+ } catch (RuntimeException e) {
+ builder.down();
+ }
+ return builder.build();
+ }
+}
diff --git a/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/runtime/RedisAPIsProducer.java b/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/runtime/RedisAPIsProducer.java
new file mode 100644
index 00000000000000..8d41c42213e2da
--- /dev/null
+++ b/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/runtime/RedisAPIsProducer.java
@@ -0,0 +1,92 @@
+package io.quarkus.vertx.redis.runtime;
+
+import javax.annotation.PreDestroy;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import io.quarkus.vertx.redis.SyncRedisAPI;
+import io.vertx.core.Vertx;
+import io.vertx.redis.client.Redis;
+import io.vertx.redis.client.RedisAPI;
+import io.vertx.redis.client.RedisOptions;
+
+@ApplicationScoped
+public class RedisAPIsProducer {
+ static long timeout = 10;
+
+ @Inject
+ Vertx vertx;
+
+ Redis redisClient;
+
+ RedisAPI redisAPI;
+
+ SyncRedisAPI syncRedisAPI;
+
+ io.vertx.axle.redis.client.Redis axleRedisClient;
+
+ io.vertx.axle.redis.client.RedisAPI axleRedisAPI;
+
+ io.vertx.mutiny.redis.client.Redis mutinyRedisClient;
+
+ io.vertx.mutiny.redis.client.RedisAPI mutinyRedisAPI;
+
+ void initialize(RedisOptions redisOptions) {
+ redisClient = Redis.createClient(vertx, redisOptions);
+ redisAPI = RedisAPI.api(redisClient);
+ axleRedisClient = io.vertx.axle.redis.client.Redis.newInstance(redisClient);
+ axleRedisAPI = io.vertx.axle.redis.client.RedisAPI.api(axleRedisClient);
+ mutinyRedisClient = io.vertx.mutiny.redis.client.Redis.newInstance(redisClient);
+ mutinyRedisAPI = io.vertx.mutiny.redis.client.RedisAPI.api(mutinyRedisClient);
+ syncRedisAPI = new SyncRedisAPIImpl(axleRedisAPI, timeout);
+ }
+
+ @Produces
+ @Singleton
+ Redis redis() {
+ return redisClient;
+ }
+
+ @Produces
+ @Singleton
+ RedisAPI redisAPI() {
+ return redisAPI;
+ }
+
+ @Produces
+ @Singleton
+ SyncRedisAPI syncRedisAPI() {
+ return syncRedisAPI;
+ }
+
+ @Produces
+ @Singleton
+ io.vertx.axle.redis.client.Redis axleRedisClient() {
+ return axleRedisClient;
+ }
+
+ @Produces
+ @Singleton
+ io.vertx.axle.redis.client.RedisAPI axleRedisAPI() {
+ return axleRedisAPI;
+ }
+
+ @Produces
+ @Singleton
+ io.vertx.mutiny.redis.client.Redis mutinyRedisClient() {
+ return mutinyRedisClient;
+ }
+
+ @Produces
+ @Singleton
+ io.vertx.mutiny.redis.client.RedisAPI mutinyRedisAPI() {
+ return mutinyRedisAPI;
+ }
+
+ @PreDestroy
+ public void close() {
+ this.redis().close();
+ }
+}
diff --git a/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/runtime/RedisConfig.java b/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/runtime/RedisConfig.java
new file mode 100644
index 00000000000000..855a078ca0720a
--- /dev/null
+++ b/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/runtime/RedisConfig.java
@@ -0,0 +1,45 @@
+package io.quarkus.vertx.redis.runtime;
+
+import java.net.InetSocketAddress;
+import java.time.Duration;
+import java.util.Optional;
+import java.util.Set;
+
+import io.quarkus.runtime.annotations.ConfigItem;
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+import io.vertx.redis.client.RedisClientType;
+
+@ConfigRoot(phase = ConfigPhase.RUN_TIME)
+public class RedisConfig {
+
+ /**
+ * The redis password
+ */
+ @ConfigItem
+ public Optional password;
+
+ /**
+ * The redis hosts
+ */
+ @ConfigItem(defaultValue = "localhost:6379")
+ public Optional> hosts;
+
+ /**
+ * The redis database
+ */
+ @ConfigItem
+ public int database;
+
+ /**
+ * The maximum delay to wait before a blocking command to redis server times out
+ */
+ @ConfigItem(defaultValue = "10")
+ public Optional timeout;
+
+ /**
+ * The redis client type
+ */
+ @ConfigItem(defaultValue = "standalone")
+ public RedisClientType clientType;
+}
diff --git a/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/runtime/SyncRedisAPIImpl.java b/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/runtime/SyncRedisAPIImpl.java
new file mode 100644
index 00000000000000..c9048008ec8f96
--- /dev/null
+++ b/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/runtime/SyncRedisAPIImpl.java
@@ -0,0 +1,1036 @@
+package io.quarkus.vertx.redis.runtime;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import io.quarkus.vertx.redis.SyncRedisAPI;
+import io.vertx.axle.redis.client.RedisAPI;
+import io.vertx.redis.client.Response;
+
+class SyncRedisAPIImpl implements SyncRedisAPI {
+
+ private final RedisAPI redisAPI;
+ private final long timeout;
+
+ public SyncRedisAPIImpl(RedisAPI redisAPI, long timeout) {
+ this.redisAPI = redisAPI;
+ this.timeout = timeout;
+ }
+
+ @Override
+ public void close() {
+ redisAPI.close();
+ }
+
+ @Override
+ public Response append(String arg0, String arg1) {
+ return await(redisAPI.append(arg0, arg1));
+ }
+
+ @Override
+ public Response asking() {
+ return await(redisAPI.asking());
+ }
+
+ @Override
+ public Response auth(String arg0) {
+ return await(redisAPI.auth(arg0));
+ }
+
+ @Override
+ public Response bgrewriteaof() {
+ return await(redisAPI.bgrewriteaof());
+ }
+
+ @Override
+ public Response bgsave(List args) {
+ return await(redisAPI.bgsave(args));
+ }
+
+ @Override
+ public Response bitcount(List args) {
+ return await(redisAPI.bitcount(args));
+ }
+
+ @Override
+ public Response bitfield(List args) {
+ return await(redisAPI.bitfield(args));
+ }
+
+ @Override
+ public Response bitop(List args) {
+ return await(redisAPI.bitop(args));
+ }
+
+ @Override
+ public Response bitpos(List args) {
+ return await(redisAPI.bitpos(args));
+ }
+
+ @Override
+ public Response blpop(List args) {
+ return await(redisAPI.blpop(args));
+ }
+
+ @Override
+ public Response brpop(List args) {
+ return await(redisAPI.brpop(args));
+ }
+
+ @Override
+ public Response brpoplpush(String arg0, String arg1, String arg2) {
+ return await(redisAPI.brpoplpush(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response bzpopmax(List args) {
+ return await(redisAPI.bzpopmax(args));
+ }
+
+ @Override
+ public Response bzpopmin(List args) {
+ return await(redisAPI.bzpopmin(args));
+ }
+
+ @Override
+ public Response client(List args) {
+ return await(redisAPI.client(args));
+ }
+
+ @Override
+ public Response cluster(List args) {
+ return await(redisAPI.cluster(args));
+ }
+
+ @Override
+ public Response command() {
+ return await(redisAPI.command());
+ }
+
+ @Override
+ public Response config(List args) {
+ return await(redisAPI.config(args));
+ }
+
+ @Override
+ public Response dbsize() {
+ return await(redisAPI.dbsize());
+ }
+
+ @Override
+ public Response debug(List args) {
+ return await(redisAPI.debug(args));
+ }
+
+ @Override
+ public Response decr(String arg0) {
+ return await(redisAPI.decr(arg0));
+ }
+
+ @Override
+ public Response decrby(String arg0, String arg1) {
+ return await(redisAPI.decrby(arg0, arg1));
+ }
+
+ @Override
+ public Response del(List args) {
+ return await(redisAPI.del(args));
+ }
+
+ @Override
+ public Response discard() {
+ return await(redisAPI.discard());
+ }
+
+ @Override
+ public Response dump(String arg0) {
+ return await(redisAPI.dump(arg0));
+ }
+
+ @Override
+ public Response echo(String arg0) {
+ return await(redisAPI.echo(arg0));
+ }
+
+ @Override
+ public Response eval(List args) {
+ return await(redisAPI.eval(args));
+ }
+
+ @Override
+ public Response evalsha(List args) {
+ return await(redisAPI.evalsha(args));
+ }
+
+ @Override
+ public Response exec() {
+ return await(redisAPI.exec());
+ }
+
+ @Override
+ public Response exists(List args) {
+ return await(redisAPI.exists(args));
+ }
+
+ @Override
+ public Response expire(String arg0, String arg1) {
+ return await(redisAPI.expire(arg0, arg1));
+ }
+
+ @Override
+ public Response expireat(String arg0, String arg1) {
+ return await(redisAPI.expireat(arg0, arg1));
+ }
+
+ @Override
+ public Response flushall(List args) {
+ return await(redisAPI.flushall(args));
+ }
+
+ @Override
+ public Response flushdb(List args) {
+ return await(redisAPI.flushdb(args));
+ }
+
+ @Override
+ public Response geoadd(List args) {
+ return await(redisAPI.geoadd(args));
+ }
+
+ @Override
+ public Response geodist(List args) {
+ return await(redisAPI.geodist(args));
+ }
+
+ @Override
+ public Response geohash(List args) {
+ return await(redisAPI.geohash(args));
+ }
+
+ @Override
+ public Response geopos(List args) {
+ return await(redisAPI.geopos(args));
+ }
+
+ @Override
+ public Response georadius(List args) {
+ return await(redisAPI.georadius(args));
+ }
+
+ @Override
+ public Response georadiusRo(List args) {
+ return await(redisAPI.georadiusRo(args));
+ }
+
+ @Override
+ public Response georadiusbymember(List args) {
+ return await(redisAPI.georadiusbymember(args));
+ }
+
+ @Override
+ public Response georadiusbymemberRo(List args) {
+ return await(redisAPI.georadiusbymemberRo(args));
+ }
+
+ @Override
+ public Response get(String arg0) {
+ return await(redisAPI.get(arg0));
+ }
+
+ @Override
+ public Response getbit(String arg0, String arg1) {
+ return await(redisAPI.getbit(arg0, arg1));
+ }
+
+ @Override
+ public Response getrange(String arg0, String arg1, String arg2) {
+ return await(redisAPI.getrange(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response getset(String arg0, String arg1) {
+ return await(redisAPI.getset(arg0, arg1));
+ }
+
+ @Override
+ public Response hdel(List args) {
+ return await(redisAPI.hdel(args));
+ }
+
+ @Override
+ public Response hexists(String arg0, String arg1) {
+ return await(redisAPI.hexists(arg0, arg1));
+ }
+
+ @Override
+ public Response hget(String arg0, String arg1) {
+ return await(redisAPI.hget(arg0, arg1));
+ }
+
+ @Override
+ public Response hgetall(String arg0) {
+ return await(redisAPI.hgetall(arg0));
+ }
+
+ @Override
+ public Response hincrby(String arg0, String arg1, String arg2) {
+ return await(redisAPI.hincrby(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response hincrbyfloat(String arg0, String arg1, String arg2) {
+ return await(redisAPI.hincrbyfloat(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response hkeys(String arg0) {
+ return await(redisAPI.hkeys(arg0));
+ }
+
+ @Override
+ public Response hlen(String arg0) {
+ return await(redisAPI.hlen(arg0));
+ }
+
+ @Override
+ public Response hmget(List args) {
+ return await(redisAPI.hmget(args));
+ }
+
+ @Override
+ public Response hmset(List args) {
+ return await(redisAPI.hmset(args));
+ }
+
+ @Override
+ public Response host(List args) {
+ return await(redisAPI.host(args));
+ }
+
+ @Override
+ public Response hscan(List args) {
+ return await(redisAPI.hscan(args));
+ }
+
+ @Override
+ public Response hset(List args) {
+ return await(redisAPI.hset(args));
+ }
+
+ @Override
+ public Response hsetnx(String arg0, String arg1, String arg2) {
+ return await(redisAPI.hsetnx(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response hstrlen(String arg0, String arg1) {
+ return await(redisAPI.hstrlen(arg0, arg1));
+ }
+
+ @Override
+ public Response hvals(String arg0) {
+ return await(redisAPI.hvals(arg0));
+ }
+
+ @Override
+ public Response incr(String arg0) {
+ return await(redisAPI.incr(arg0));
+ }
+
+ @Override
+ public Response incrby(String arg0, String arg1) {
+ return await(redisAPI.incrby(arg0, arg1));
+ }
+
+ @Override
+ public Response incrbyfloat(String arg0, String arg1) {
+ return await(redisAPI.incrbyfloat(arg0, arg1));
+ }
+
+ @Override
+ public Response info(List args) {
+ return await(redisAPI.info(args));
+ }
+
+ @Override
+ public Response keys(String arg0) {
+ return await(redisAPI.keys(arg0));
+ }
+
+ @Override
+ public Response lastsave() {
+ return await(redisAPI.lastsave());
+ }
+
+ @Override
+ public Response latency(List args) {
+ return await(redisAPI.latency(args));
+ }
+
+ @Override
+ public Response lindex(String arg0, String arg1) {
+ return await(redisAPI.lindex(arg0, arg1));
+ }
+
+ @Override
+ public Response linsert(String arg0, String arg1, String arg2, String arg3) {
+ return await(redisAPI.linsert(arg0, arg1, arg2, arg3));
+ }
+
+ @Override
+ public Response llen(String arg0) {
+ return await(redisAPI.llen(arg0));
+ }
+
+ @Override
+ public Response lolwut(List args) {
+ return await(redisAPI.lolwut(args));
+ }
+
+ @Override
+ public Response lpop(String arg0) {
+ return await(redisAPI.lpop(arg0));
+ }
+
+ @Override
+ public Response lpush(List args) {
+ return await(redisAPI.lpush(args));
+ }
+
+ @Override
+ public Response lpushx(List args) {
+ return await(redisAPI.lpushx(args));
+ }
+
+ @Override
+ public Response lrange(String arg0, String arg1, String arg2) {
+ return await(redisAPI.lrange(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response lrem(String arg0, String arg1, String arg2) {
+ return await(redisAPI.lrem(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response lset(String arg0, String arg1, String arg2) {
+ return await(redisAPI.lset(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response ltrim(String arg0, String arg1, String arg2) {
+ return await(redisAPI.ltrim(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response memory(List args) {
+ return await(redisAPI.memory(args));
+ }
+
+ @Override
+ public Response mget(List args) {
+ return await(redisAPI.mget(args));
+ }
+
+ @Override
+ public Response migrate(List args) {
+ return await(redisAPI.migrate(args));
+ }
+
+ @Override
+ public Response module(List args) {
+ return await(redisAPI.module(args));
+ }
+
+ @Override
+ public Response monitor() {
+ return await(redisAPI.monitor());
+ }
+
+ @Override
+ public Response move(String arg0, String arg1) {
+ return await(redisAPI.move(arg0, arg1));
+ }
+
+ @Override
+ public Response mset(List args) {
+ return await(redisAPI.mset(args));
+ }
+
+ @Override
+ public Response msetnx(List args) {
+ return await(redisAPI.msetnx(args));
+ }
+
+ @Override
+ public Response multi() {
+ return await(redisAPI.multi());
+ }
+
+ @Override
+ public Response object(List args) {
+ return await(redisAPI.object(args));
+ }
+
+ @Override
+ public Response persist(String arg0) {
+ return await(redisAPI.persist(arg0));
+ }
+
+ @Override
+ public Response pexpire(String arg0, String arg1) {
+ return await(redisAPI.pexpire(arg0, arg1));
+ }
+
+ @Override
+ public Response pexpireat(String arg0, String arg1) {
+ return await(redisAPI.pexpireat(arg0, arg1));
+ }
+
+ @Override
+ public Response pfadd(List args) {
+ return await(redisAPI.pfadd(args));
+ }
+
+ @Override
+ public Response pfcount(List args) {
+ return await(redisAPI.pfcount(args));
+ }
+
+ @Override
+ public Response pfdebug(List args) {
+ return await(redisAPI.pfdebug(args));
+ }
+
+ @Override
+ public Response pfmerge(List args) {
+ return await(redisAPI.pfmerge(args));
+ }
+
+ @Override
+ public Response pfselftest() {
+ return await(redisAPI.pfselftest());
+ }
+
+ @Override
+ public Response ping(List args) {
+ return await(redisAPI.ping(args));
+ }
+
+ @Override
+ public Response post(List args) {
+ return await(redisAPI.post(args));
+ }
+
+ @Override
+ public Response psetex(String arg0, String arg1, String arg2) {
+ return await(redisAPI.psetex(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response psubscribe(List args) {
+ return await(redisAPI.psubscribe(args));
+ }
+
+ @Override
+ public Response psync(String arg0, String arg1) {
+ return await(redisAPI.psync(arg0, arg1));
+ }
+
+ @Override
+ public Response pttl(String arg0) {
+ return await(redisAPI.pttl(arg0));
+ }
+
+ @Override
+ public Response publish(String arg0, String arg1) {
+ return await(redisAPI.publish(arg0, arg1));
+ }
+
+ @Override
+ public Response pubsub(List args) {
+ return await(redisAPI.pubsub(args));
+ }
+
+ @Override
+ public Response punsubscribe(List args) {
+ return await(redisAPI.punsubscribe(args));
+ }
+
+ @Override
+ public Response randomkey() {
+ return await(redisAPI.randomkey());
+ }
+
+ @Override
+ public Response readonly() {
+ return await(redisAPI.readonly());
+ }
+
+ @Override
+ public Response readwrite() {
+ return await(redisAPI.readwrite());
+ }
+
+ @Override
+ public Response rename(String arg0, String arg1) {
+ return await(redisAPI.rename(arg0, arg1));
+ }
+
+ @Override
+ public Response renamenx(String arg0, String arg1) {
+ return await(redisAPI.renamenx(arg0, arg1));
+ }
+
+ @Override
+ public Response replconf(List args) {
+ return await(redisAPI.replconf(args));
+ }
+
+ @Override
+ public Response replicaof(String arg0, String arg1) {
+ return await(redisAPI.replicaof(arg0, arg1));
+ }
+
+ @Override
+ public Response restore(List args) {
+ return await(redisAPI.restore(args));
+ }
+
+ @Override
+ public Response restoreAsking(List args) {
+ return await(redisAPI.restoreAsking(args));
+ }
+
+ @Override
+ public Response role() {
+ return await(redisAPI.role());
+ }
+
+ @Override
+ public Response rpop(String arg0) {
+ return await(redisAPI.rpop(arg0));
+ }
+
+ @Override
+ public Response rpoplpush(String arg0, String arg1) {
+ return await(redisAPI.rpoplpush(arg0, arg1));
+ }
+
+ @Override
+ public Response rpush(List args) {
+ return await(redisAPI.rpush(args));
+ }
+
+ @Override
+ public Response rpushx(List args) {
+ return await(redisAPI.rpushx(args));
+ }
+
+ @Override
+ public Response sadd(List args) {
+ return await(redisAPI.sadd(args));
+ }
+
+ @Override
+ public Response save() {
+ return await(redisAPI.save());
+ }
+
+ @Override
+ public Response scan(List args) {
+ return await(redisAPI.scan(args));
+ }
+
+ @Override
+ public Response scard(String arg0) {
+ return await(redisAPI.scard(arg0));
+ }
+
+ @Override
+ public Response script(List args) {
+ return await(redisAPI.script(args));
+ }
+
+ @Override
+ public Response sdiff(List args) {
+ return await(redisAPI.sdiff(args));
+ }
+
+ @Override
+ public Response sdiffstore(List args) {
+ return await(redisAPI.sdiffstore(args));
+ }
+
+ @Override
+ public Response select(String arg0) {
+ return await(redisAPI.select(arg0));
+ }
+
+ @Override
+ public Response set(List args) {
+ return await(redisAPI.set(args));
+ }
+
+ @Override
+ public Response setbit(String arg0, String arg1, String arg2) {
+ return await(redisAPI.setbit(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response setex(String arg0, String arg1, String arg2) {
+ return await(redisAPI.setex(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response setnx(String arg0, String arg1) {
+ return await(redisAPI.setnx(arg0, arg1));
+ }
+
+ @Override
+ public Response setrange(String arg0, String arg1, String arg2) {
+ return await(redisAPI.setrange(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response shutdown(List args) {
+ return await(redisAPI.shutdown(args));
+ }
+
+ @Override
+ public Response sinter(List args) {
+ return await(redisAPI.sinter(args));
+ }
+
+ @Override
+ public Response sinterstore(List args) {
+ return await(redisAPI.sinterstore(args));
+ }
+
+ @Override
+ public Response sismember(String arg0, String arg1) {
+ return await(redisAPI.sismember(arg0, arg1));
+ }
+
+ @Override
+ public Response slaveof(String arg0, String arg1) {
+ return await(redisAPI.slaveof(arg0, arg1));
+ }
+
+ @Override
+ public Response slowlog(List args) {
+ return await(redisAPI.slowlog(args));
+ }
+
+ @Override
+ public Response smembers(String arg0) {
+ return await(redisAPI.smembers(arg0));
+ }
+
+ @Override
+ public Response smove(String arg0, String arg1, String arg2) {
+ return await(redisAPI.smove(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response sort(List args) {
+ return await(redisAPI.sort(args));
+ }
+
+ @Override
+ public Response spop(List args) {
+ return await(redisAPI.spop(args));
+ }
+
+ @Override
+ public Response srandmember(List args) {
+ return await(redisAPI.srandmember(args));
+ }
+
+ @Override
+ public Response srem(List args) {
+ return await(redisAPI.srem(args));
+ }
+
+ @Override
+ public Response sscan(List args) {
+ return await(redisAPI.sscan(args));
+ }
+
+ @Override
+ public Response strlen(String arg0) {
+ return await(redisAPI.strlen(arg0));
+ }
+
+ @Override
+ public Response subscribe(List args) {
+ return await(redisAPI.subscribe(args));
+ }
+
+ @Override
+ public Response substr(String arg0, String arg1, String arg2) {
+ return await(redisAPI.substr(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response sunion(List args) {
+ return await(redisAPI.sunion(args));
+ }
+
+ @Override
+ public Response sunionstore(List args) {
+ return await(redisAPI.sunionstore(args));
+ }
+
+ @Override
+ public Response swapdb(String arg0, String arg1) {
+ return await(redisAPI.swapdb(arg0, arg1));
+ }
+
+ @Override
+ public Response sync() {
+ return await(redisAPI.sync());
+ }
+
+ @Override
+ public Response time() {
+ return await(redisAPI.time());
+ }
+
+ @Override
+ public Response touch(List args) {
+ return await(redisAPI.touch(args));
+ }
+
+ @Override
+ public Response ttl(String arg0) {
+ return await(redisAPI.ttl(arg0));
+ }
+
+ @Override
+ public Response type(String arg0) {
+ return await(redisAPI.type(arg0));
+ }
+
+ @Override
+ public Response unlink(List args) {
+ return await(redisAPI.unlink(args));
+ }
+
+ @Override
+ public Response unsubscribe(List args) {
+ return await(redisAPI.unsubscribe(args));
+ }
+
+ @Override
+ public Response unwatch() {
+ return await(redisAPI.unwatch());
+ }
+
+ @Override
+ public Response wait(String arg0, String arg1) {
+ return await(redisAPI.wait(arg0, arg1));
+ }
+
+ @Override
+ public Response watch(List args) {
+ return await(redisAPI.watch(args));
+ }
+
+ @Override
+ public Response xack(List args) {
+ return await(redisAPI.xack(args));
+ }
+
+ @Override
+ public Response xadd(List args) {
+ return await(redisAPI.xadd(args));
+ }
+
+ @Override
+ public Response xclaim(List args) {
+ return await(redisAPI.xclaim(args));
+ }
+
+ @Override
+ public Response xdel(List args) {
+ return await(redisAPI.xdel(args));
+ }
+
+ @Override
+ public Response xgroup(List args) {
+ return await(redisAPI.xgroup(args));
+ }
+
+ @Override
+ public Response xinfo(List args) {
+ return await(redisAPI.xinfo(args));
+ }
+
+ @Override
+ public Response xlen(String arg0) {
+ return await(redisAPI.xlen(arg0));
+ }
+
+ @Override
+ public Response xpending(List args) {
+ return await(redisAPI.xpending(args));
+ }
+
+ @Override
+ public Response xrange(List args) {
+ return await(redisAPI.xrange(args));
+ }
+
+ @Override
+ public Response xread(List args) {
+ return await(redisAPI.xread(args));
+ }
+
+ @Override
+ public Response xreadgroup(List args) {
+ return await(redisAPI.xreadgroup(args));
+ }
+
+ @Override
+ public Response xrevrange(List args) {
+ return await(redisAPI.xrevrange(args));
+ }
+
+ @Override
+ public Response xsetid(String arg0, String arg1) {
+ return await(redisAPI.xsetid(arg0, arg1));
+ }
+
+ @Override
+ public Response xtrim(List args) {
+ return await(redisAPI.xtrim(args));
+ }
+
+ @Override
+ public Response zadd(List args) {
+ return await(redisAPI.zadd(args));
+ }
+
+ @Override
+ public Response zcard(String arg0) {
+ return await(redisAPI.zcard(arg0));
+ }
+
+ @Override
+ public Response zcount(String arg0, String arg1, String arg2) {
+ return await(redisAPI.zcount(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response zincrby(String arg0, String arg1, String arg2) {
+ return await(redisAPI.zincrby(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response zinterstore(List args) {
+ return await(redisAPI.zinterstore(args));
+ }
+
+ @Override
+ public Response zlexcount(String arg0, String arg1, String arg2) {
+ return await(redisAPI.zlexcount(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response zpopmax(List args) {
+ return await(redisAPI.zpopmax(args));
+ }
+
+ @Override
+ public Response zpopmin(List args) {
+ return await(redisAPI.zpopmin(args));
+ }
+
+ @Override
+ public Response zrange(List args) {
+ return await(redisAPI.zrange(args));
+ }
+
+ @Override
+ public Response zrangebylex(List args) {
+ return await(redisAPI.zrangebylex(args));
+ }
+
+ @Override
+ public Response zrangebyscore(List args) {
+ return await(redisAPI.zrangebyscore(args));
+ }
+
+ @Override
+ public Response zrank(String arg0, String arg1) {
+ return await(redisAPI.zrank(arg0, arg1));
+ }
+
+ @Override
+ public Response zrem(List args) {
+ return await(redisAPI.zrem(args));
+ }
+
+ @Override
+ public Response zremrangebylex(String arg0, String arg1, String arg2) {
+ return await(redisAPI.zremrangebylex(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response zremrangebyrank(String arg0, String arg1, String arg2) {
+ return await(redisAPI.zremrangebyrank(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response zremrangebyscore(String arg0, String arg1, String arg2) {
+ return await(redisAPI.zremrangebyscore(arg0, arg1, arg2));
+ }
+
+ @Override
+ public Response zrevrange(List args) {
+ return await(redisAPI.zrevrange(args));
+ }
+
+ @Override
+ public Response zrevrangebylex(List args) {
+ return await(redisAPI.zrevrangebylex(args));
+ }
+
+ @Override
+ public Response zrevrangebyscore(List args) {
+ return await(redisAPI.zrevrangebyscore(args));
+ }
+
+ @Override
+ public Response zrevrank(String arg0, String arg1) {
+ return await(redisAPI.zrevrank(arg0, arg1));
+ }
+
+ @Override
+ public Response zscan(List args) {
+ return await(redisAPI.zscan(args));
+ }
+
+ @Override
+ public Response zscore(String arg0, String arg1) {
+ return await(redisAPI.zscore(arg0, arg1));
+ }
+
+ @Override
+ public Response zunionstore(List args) {
+ return await(redisAPI.zunionstore(args));
+ }
+
+ private Response await(CompletionStage response) {
+ try {
+ return response.toCompletableFuture().get(timeout, SECONDS).getDelegate();
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/runtime/VertxRedisRecorder.java b/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/runtime/VertxRedisRecorder.java
new file mode 100644
index 00000000000000..d544bf40862bc2
--- /dev/null
+++ b/extensions/vertx-redis/runtime/src/main/java/io/quarkus/vertx/redis/runtime/VertxRedisRecorder.java
@@ -0,0 +1,63 @@
+package io.quarkus.vertx.redis.runtime;
+
+import java.net.InetSocketAddress;
+import java.util.Optional;
+import java.util.Set;
+
+import io.quarkus.arc.runtime.BeanContainer;
+import io.quarkus.runtime.annotations.Recorder;
+import io.quarkus.runtime.configuration.ConfigurationException;
+import io.vertx.redis.client.RedisClientType;
+import io.vertx.redis.client.RedisOptions;
+
+@Recorder
+public class VertxRedisRecorder {
+ private static final char AT = '@';
+ private static final char COLON = ':';
+ private static final char SLASH = '/';
+ private static final String REDIS_SCHEME = "redis://";
+
+ public void initialize(RedisConfig config, BeanContainer container) {
+ RedisAPIsProducer producer = container.instance(RedisAPIsProducer.class);
+ RedisOptions options = new RedisOptions();
+ options.setType(config.clientType);
+
+ if (RedisClientType.STANDALONE == config.clientType) {
+ if (config.hosts.isPresent() && config.hosts.get().size() > 1) {
+ throw new ConfigurationException("Multiple hosts supplied for non clustered configuration");
+ }
+ }
+
+ if (config.hosts.isPresent()) {
+ Set hosts = config.hosts.get();
+ for (InetSocketAddress host : hosts) {
+ options.addConnectionString(buildRedisUrl(host, config.password, config.database));
+ }
+ } else {
+ InetSocketAddress defaultRedisAddress = new InetSocketAddress("localhost", 6379);
+ options.addConnectionString(buildRedisUrl(defaultRedisAddress, config.password, config.database));
+ }
+
+ if (config.timeout.isPresent()) {
+ RedisAPIsProducer.timeout = config.timeout.get().getSeconds();
+ }
+
+ producer.initialize(options);
+ }
+
+ private String buildRedisUrl(InetSocketAddress address, Optional password, int database) {
+ StringBuilder builder = new StringBuilder(REDIS_SCHEME);
+ if (password.isPresent()) {
+ builder.append(password.get());
+ builder.append(AT);
+ }
+
+ builder.append(address.getHostString());
+ builder.append(COLON);
+ builder.append(address.getPort());
+ builder.append(SLASH);
+ builder.append(database);
+
+ return builder.toString();
+ }
+}
diff --git a/extensions/vertx-redis/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/vertx-redis/runtime/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 00000000000000..e2653d0d46fc48
--- /dev/null
+++ b/extensions/vertx-redis/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,14 @@
+---
+name: "Vertx Redis"
+metadata:
+ keywords:
+ - "redis"
+ - "vertx-redis"
+ - "vertx"
+ - "vert.x"
+ - "reactive"
+ guide: "https://quarkus.io/guides/redis"
+ categories:
+ - "persistence"
+ - "reactive"
+ status: "preview"
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index 16e08046530047..33356ffccb184d 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -101,6 +101,7 @@
smallrye-graphql
jpa-without-entity
quartz
+ vertx-redis
logging-gelf
cache
qute
diff --git a/integration-tests/vertx-redis/README.md b/integration-tests/vertx-redis/README.md
new file mode 100644
index 00000000000000..d943e88df2ca13
--- /dev/null
+++ b/integration-tests/vertx-redis/README.md
@@ -0,0 +1,21 @@
+# Redis example
+
+## Running the tests
+
+By default, the tests of this module are disabled.
+
+To run, you can run the following command:
+
+```
+mvn clean install -Dtest-redis
+```
+
+NB: Tests in this module will attempt a connection to a local Redis listening on the default port.
+If you have specific requirements, you can define a specific connection URL with `-Dquarkus.redis.hosts=host:port`.
+
+
+Additionally, you can generate a native image and run the tests for this native image by adding `-Dnative`:
+
+```
+mvn clean install -Dtest-redis -Dnative
+```
diff --git a/integration-tests/vertx-redis/pom.xml b/integration-tests/vertx-redis/pom.xml
new file mode 100644
index 00000000000000..f9ec73e94f8bda
--- /dev/null
+++ b/integration-tests/vertx-redis/pom.xml
@@ -0,0 +1,154 @@
+
+
+ 4.0.0
+
+ io.quarkus
+ quarkus-integration-tests-parent
+ 999-SNAPSHOT
+ ../pom.xml
+
+
+ redis-integration-test
+ Quarkus - Redis - Integration Test
+
+
+ localhost:6379
+
+
+
+
+ io.quarkus
+ quarkus-resteasy-mutiny
+
+
+ io.quarkus
+ quarkus-vertx-redis
+
+
+ io.quarkus
+ quarkus-smallrye-health
+
+
+
+
+ io.quarkus
+ quarkus-junit5
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+ maven-surefire-plugin
+
+ true
+
+
+
+ maven-failsafe-plugin
+
+ true
+
+
+
+ io.quarkus
+ quarkus-maven-plugin
+
+
+
+ build
+
+
+
+
+
+
+
+
+
+ test-redis
+
+
+ test-redis
+
+
+
+
+
+ maven-surefire-plugin
+
+ false
+
+
+
+ maven-failsafe-plugin
+
+ false
+
+
+
+
+
+
+
+ native-image
+
+
+ native
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+
+
+
+ integration-test
+ verify
+
+
+
+ ${project.build.directory}/${project.build.finalName}-runner
+
+
+
+
+
+
+ io.quarkus
+ quarkus-maven-plugin
+
+
+ native-image
+
+ native-image
+
+
+ true
+ true
+ ${graalvmHome}
+ -H:+TraceClassInitialization
+
+
+
+
+
+
+
+
+
+
diff --git a/integration-tests/vertx-redis/src/main/java/io/quarkus/vertx/redis/it/RedisResource.java b/integration-tests/vertx-redis/src/main/java/io/quarkus/vertx/redis/it/RedisResource.java
new file mode 100644
index 00000000000000..56500d930b9386
--- /dev/null
+++ b/integration-tests/vertx-redis/src/main/java/io/quarkus/vertx/redis/it/RedisResource.java
@@ -0,0 +1,55 @@
+package io.quarkus.vertx.redis.it;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
+import io.quarkus.vertx.redis.SyncRedisAPI;
+import io.smallrye.mutiny.Uni;
+import io.vertx.mutiny.redis.client.RedisAPI;
+
+import java.util.Arrays;
+
+@Path("/quarkus-redis")
+@ApplicationScoped
+public class RedisResource {
+ @Inject
+ SyncRedisAPI syncRedisAPI;
+
+ @Inject
+ RedisAPI reactiveRedisAPI;
+
+ // synchronous
+ @GET
+ @Path("/sync/{key}")
+ public String getSync(@PathParam("key") String key) {
+ return syncRedisAPI.get(key).toString();
+ }
+
+ @POST
+ @Path("/sync/{key}")
+ public void setSync(@PathParam("key") String key, String value) {
+ this.syncRedisAPI.set(Arrays.asList(key, value));
+ }
+
+ // reactive
+ @GET
+ @Path("/reactive/{key}")
+ public Uni getReactive(@PathParam("key") String key) {
+ return reactiveRedisAPI
+ .get(key)
+ .map(response -> response.toString());
+ }
+
+ @POST
+ @Path("/reactive/{key}")
+ public Uni setReactive(@PathParam("key") String key, String value) {
+ return this.reactiveRedisAPI
+ .set(Arrays.asList(key, value))
+ .map(response -> null);
+ }
+
+}
diff --git a/integration-tests/vertx-redis/src/test/java/io/quarkus/vertx/redis/it/HealthCheckIT.java b/integration-tests/vertx-redis/src/test/java/io/quarkus/vertx/redis/it/HealthCheckIT.java
new file mode 100644
index 00000000000000..e7fde15660cabd
--- /dev/null
+++ b/integration-tests/vertx-redis/src/test/java/io/quarkus/vertx/redis/it/HealthCheckIT.java
@@ -0,0 +1,7 @@
+package io.quarkus.vertx.redis.it;
+
+import io.quarkus.test.junit.NativeImageTest;
+
+@NativeImageTest
+public class HealthCheckIT extends HealthCheckTest {
+}
diff --git a/integration-tests/vertx-redis/src/test/java/io/quarkus/vertx/redis/it/HealthCheckTest.java b/integration-tests/vertx-redis/src/test/java/io/quarkus/vertx/redis/it/HealthCheckTest.java
new file mode 100644
index 00000000000000..25a6c7767dbf9a
--- /dev/null
+++ b/integration-tests/vertx-redis/src/test/java/io/quarkus/vertx/redis/it/HealthCheckTest.java
@@ -0,0 +1,24 @@
+package io.quarkus.vertx.redis.it;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+
+import org.junit.jupiter.api.Test;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+
+@QuarkusTest
+public class HealthCheckTest {
+ @Test
+ public void testHealthCheck() {
+ RestAssured.when().get("/health").then()
+ .contentType(ContentType.JSON)
+ .header("Content-Type", containsString("charset=UTF-8"))
+ .body("status", is("UP"),
+ "checks.status", containsInAnyOrder("UP"),
+ "checks.name", containsInAnyOrder("Redis connection health check"));
+ }
+}
diff --git a/integration-tests/vertx-redis/src/test/java/io/quarkus/vertx/redis/it/QuarkusRedisIT.java b/integration-tests/vertx-redis/src/test/java/io/quarkus/vertx/redis/it/QuarkusRedisIT.java
new file mode 100644
index 00000000000000..7e3313672d603e
--- /dev/null
+++ b/integration-tests/vertx-redis/src/test/java/io/quarkus/vertx/redis/it/QuarkusRedisIT.java
@@ -0,0 +1,8 @@
+package io.quarkus.vertx.redis.it;
+
+import io.quarkus.test.junit.NativeImageTest;
+
+@NativeImageTest
+class QuarkusRedisIT extends QuarkusRedisTest {
+
+}
diff --git a/integration-tests/vertx-redis/src/test/java/io/quarkus/vertx/redis/it/QuarkusRedisTest.java b/integration-tests/vertx-redis/src/test/java/io/quarkus/vertx/redis/it/QuarkusRedisTest.java
new file mode 100644
index 00000000000000..2eedc1c7aaa5d8
--- /dev/null
+++ b/integration-tests/vertx-redis/src/test/java/io/quarkus/vertx/redis/it/QuarkusRedisTest.java
@@ -0,0 +1,50 @@
+package io.quarkus.vertx.redis.it;
+
+import org.hamcrest.CoreMatchers;
+import org.junit.jupiter.api.Test;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+
+@QuarkusTest
+class QuarkusRedisTest {
+ private static final String SYNC_KEY = "sync-key";
+ private static final String SYNC_VALUE = "sync-value";
+
+ private static final String REACTIVE_KEY = "reactive-key";
+ private static final String REACTIVE_VALUE = "reactive-value";
+
+ @Test
+ public void sync() {
+ RestAssured.given()
+ .body(SYNC_VALUE)
+ .when()
+ .post("/quarkus-redis/sync/" + SYNC_KEY)
+ .then()
+ .statusCode(204);
+
+ RestAssured.given()
+ .when()
+ .get("/quarkus-redis/sync/" + SYNC_KEY)
+ .then()
+ .statusCode(200)
+ .body(CoreMatchers.is(SYNC_VALUE));
+ }
+
+ @Test
+ public void reactive() {
+ RestAssured.given()
+ .body(REACTIVE_VALUE)
+ .when()
+ .post("/quarkus-redis/reactive/" + REACTIVE_KEY)
+ .then()
+ .statusCode(204);
+
+ RestAssured.given()
+ .when()
+ .get("/quarkus-redis/reactive/" + REACTIVE_KEY)
+ .then()
+ .statusCode(200)
+ .body(CoreMatchers.is(REACTIVE_VALUE));
+ }
+}