Quarkus - Dapr

Introduction

What is Dapr?

Dapr is a portable, event-driven runtime that makes it easy for any developer to build resilient, stateless and stateful applications that run on the cloud and edge and embraces the diversity of languages and developer frameworks.

Leveraging the benefits of a sidecar architecture, Dapr helps you tackle the challenges that come with building microservices and keeps your code platform agnostic.

For more information about Dapr, please go https://dapr.io/.

What is Quarkus-Dapr?

Quarkus Dapr is a Quarkus extension to integrate with Dapr.

Quarkus Dapr Extension enables Java developers to create ultra lightweight Java native applications for Function Computing and FaaS scenes, which is also particularly suitable for running as serverless.

With the help of Dapr, these ultra lightweight Java native applications can easily interact with external application and resources. Dapr provides many useful building blocks to build modern distributed application: service invocation, state management, input/output bindings, publish & subscribe, secret management…​…​

Because of the advantages of sidecar model, the native applications can benefit from Dapr’s distributed capabilities while remain lightweight without introducing too many dependencies. This is not only helping to keep the size of java native applications, but also making the native applications easy to build as native images.

Installation

If you want to use this extension, you need to add the io.quarkiverse.dapr:quarkus-dapr extension first. In your pom.xml file, add:

<dependency>
    <groupId>io.quarkiverse.dapr</groupId>
    <artifactId>quarkus-dapr</artifactId>
</dependency>

Examples

With Quarkus Dapr Extension, it’s pretty easy for java developers.

publish & subscribe

To publish events to your message broker, just inject a dapr client to your bean and call it’s publishEvent() method:

@Inject
SyncDaprClient dapr;

dapr.publishEvent("messagebus", "topic1", content.getBytes(StandardCharsets.UTF_8), new HashMap<>());

To subscribe events for your message broker, adding some annotations on your method is enough:

@POST
@Path("/topic1")
@Topic(name = "topic1", pubsubName = "messagebus")
public String eventOnTopic2(String content) {......}

In the attributes name, pubsubName, and match of the @Topic annotation, it is possible to set a config property to be loaded at runtime.

@POST
@Path("/topic6")
@Topic(name = "${topic6}", pubsubName = "${pubsub.topic6}", rule = @Rule(match = "${match.rule6}", priority = 1))
public String eventOnTopic6(String content) {......}

For more details and hands-on experiences, please reference to our Demo.

Extension Configuration Reference

Dapr DevServices

Quarkus Dapr Extension provides a DevService to enhance your experience with Quarkus and Dapr.

Enabling / Disabling Dev Services for Dapr

Dev Services for Dapr are disabled by default unless:

  • quarkus.dapr.devservices.enabled is set to true

Setting Dapr image

Dev Services for Dapr uses the latest daprio/daprd image (diagrid/daprd:latest). You can change this image using the quarkus.dapr.devservices.image-name property.

Using In-Memory Dapr Components

The component name for Pub/Sub in-memory is called pubsub and for State Store in-memory is called kvstore.

Example of code using Pub/Sub and State Store in-memory:

DaprResource.java
package io.dapr.docs;

import io.dapr.Topic;
import io.dapr.client.domain.CloudEvent;
import io.dapr.client.domain.State;
import io.quarkiverse.dapr.core.SyncDaprClient;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import java.util.Map;
import java.util.UUID;

@Path("/dapr")
public class DaprResource {

    @Inject
    SyncDaprClient client;

    @POST
    @Path("/state")
    public Response saveState() {
        client.saveState("kvstore", "identity", UUID.randomUUID().toString()); (1)
        return Response.ok().build();
    }

    @GET
    @Path("/state")
    public Response getState() {
        State<String> state = client.getState("kvstore", "identity", String.class);
        return Response.ok(Map.of("identity", state.getValue())).build();
    }

    @POST
    @Path("/pub")
    public void pub() {
        client.publishEvent("pubsub", "topicName", "Hello from Quarkus!"); (2)
    }

    @POST
    @Topic(name = "topicName") (3)
    @Path("/sub") (4)
    public void sub(CloudEvent<String> event) {
        System.out.println("Received event: " + event.getData());
    }
}
1 kvstore is the name of the in-memory State Store component created by DevServices, and identity is the key used to store the value.
2 pubsub is the name of the in-memory Pub/Sub component created by DevServices, and topicName is the name of the topic used to publish the message (Hello from Quarkus!).
3 topicName is the name of the topic used to subscribe to the message, you need to add the @io.dapr.Topic annotation to map the topic. If you want to add a custom Dapr component, you need to add it to the src/main/resources/components folder.
4 The value sub can be any value, it is used behind the scenes to map the endpoint to the topic.
The default quarkus.dapr.default-pub-sub value is redis, so you need to change to pubsub if you want to use the in-memory Pub/Sub component.

Adding Dapr Components

By default, Dapr DevServices create a Dapr container containing in-memory Pub/Sub and in-memory State Store building blocks. If you want to use a non-in-memory Dapr component, you need to add it to the src/main/resources/components folder.

Example of Pub/Sub using Redis.

src/main/resources/components/redis-pubsub.yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: pubsub
spec:
  type: pubsub.redis
  version: v1
  metadata:
    - name: redisHost
      value: localhost:6379
    - name: redisPassword
      value: ""

Example of State Store using Redis:

src/main/resources/components/redis-statestore.yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.redis
  version: v1
  metadata:
    - name: keyPrefix
      value: name
    - name: redisHost
      value: localhost:6379
    - name: redisPassword
      value: ""

Network

By default, Dev Services for Dapr utilize a network named dapr. Dev Services search for a Docker Network named dapr; if one does not exist, Dev Services create it.