Integrating RabbitMQ in Micronaut: A Step-by-Step Guide

RabbitMq in Micronaut

RabbitMq in Micronaut

RabbitMQ is a robust and versatile message broker that can be integrated into your Micronaut applications to handle asynchronous communication. It’s especially useful for scenarios where different parts of your application need to communicate without waiting for immediate responses. In this guide, we’ll walk you through the process of integrating RabbitMQ with Micronaut.

Prerequisites

Before we dive into the integration process, make sure you have the following prerequisites in place:

  1. Micronaut Application: You should have a Micronaut application up and running. If you don’t have one, you can quickly create a new project using Micronaut CLI or any preferred method.
  2. Docker: Ensure you have a RabbitMQ server accessible or docker configured to install Rabbit MQ. You can either set up a local instance or use a cloud-based service. If not done no issue as we will setup a local rabbitMq server using Docker.

Integrating RabbitMQ in Micronaut

Follow these steps to integrate RabbitMQ with your Micronaut application:

Step 1: Run RabbitMq Application

docker run -d --name my-rabbitmq -p 5672:5672 -p 15672:15672 \
  -e RABBITMQ_DEFAULT_USER=guest -e RABBITMQ_DEFAULT_PASS=guest \
  rabbitmq:3.11-management

This command does the following:

  • -d: Runs the container in detached mode.
  • --name my-rabbitmq: Names the container as “my-rabbitmq.”
  • -p 5672:5672 -p 15672:15672: Maps the container’s ports to the host machine.
  • -e RABBITMQ_DEFAULT_USER=guest -e RABBITMQ_DEFAULT_PASS=guest: Sets environment variables for the RabbitMQ default username and password.
  • rabbitmq:3.11-management: Specifies the Docker image to use, including the RabbitMQ version and the management plugin.
RabbitMq up and Running

Step 2: Add RabbitMQ Dependency

Make sure you have the micronaut-rabbitmq dependency in your build.gradle or build.gradle.kts file:

implementation("io.micronaut.rabbitmq:micronaut-rabbitmq:3.4.0")

Step 3: Configure RabbitMQ Connection

In your application.yml or application.properties file, configure the RabbitMQ connection details. Replace the placeholders with your RabbitMQ server information.

rabbitmq:
  uri: amqp://${RABBITMQ_USER:guest}:${RABBITMQ_PASS:guest}@${RABBITMQ_HOST:localhost}:${RABBITMQ_PORT:5672}
  consumer-executor: rabbit
  • rabbitmq is a configuration section specifically for RabbitMQ settings within the Micronaut application.
  • uri is the URI (Uniform Resource Identifier) that specifies how to connect to the RabbitMQ server. It’s constructed as follows:
    • amqp://: This is the URI scheme for the AMQP (Advanced Message Queuing Protocol), which is the protocol used by RabbitMQ.
    • ${RABBITMQ_USER:guest}:${RABBITMQ_PASS:guest}: This part defines the username and password for connecting to RabbitMQ. It uses environment variables for flexibility. If the RABBITMQ_USER and RABBITMQ_PASS environment variables are set, they will be used as the username and password. If not, the default values “guest” for both username and password are used.
    • @${RABBITMQ_HOST:localhost}:${RABBITMQ_PORT:5672}: This part specifies the RabbitMQ server’s hostname and port. Similarly, it uses environment variables for flexibility. If RABBITMQ_HOST is set, it will be used as the hostname. If not, the default value “localhost” is used. Likewise, if RABBITMQ_PORT is set, it will be used as the port number. If not, the default port number 5672 is used.
  • consumer-executor: rabbit sets the consumer executor to “rabbit.” This likely specifies the executor that Micronaut will use for running consumers (message consumers) that process messages from RabbitMQ. In this case, it’s configured to use the “rabbit” executor.

Step 4: Create a Publisher

To send messages to RabbitMQ, we have to create Publisher for RabbitMq

package com.example.event

import io.micronaut.rabbitmq.annotation.Binding
import io.micronaut.rabbitmq.annotation.RabbitClient

@RabbitClient("rabbitmq-demo")
interface Publisher {

    @Binding("event.number")
    suspend fun emitEventNumber(eventNumber: Long)
}

Step 5: Create a RabbitMQ Consumer

In Micronaut, you can create RabbitMQ consumers easily by defining a method in a Micronaut bean and annotating it with @RabbitListener. For example:

package com.example.event

import com.example.util.logger
import io.micronaut.rabbitmq.annotation.Queue
import io.micronaut.rabbitmq.annotation.RabbitListener

@RabbitListener
class Consumer {
    @Queue("event-number", prefetch = 1)
    fun consumeEventNumber(eventNumber: Long) {
        logger().error(eventNumber.toString())
    }
}

Step 6: Declare Queue and Bind to Exchange

package com.example.common

import com.rabbitmq.client.Channel
import io.micronaut.rabbitmq.connect.ChannelInitializer
import io.micronaut.runtime.event.annotation.EventListener
import io.micronaut.runtime.server.event.ServerStartupEvent
import jakarta.inject.Singleton
@Singleton
class RabbitMqBootstrap : ChannelInitializer() {

    @EventListener
    fun onStartupEvent(@Suppress("UNUSED_PARAMETER") event: ServerStartupEvent) {
        initialize(null, "")
    }

    override fun initialize(channel: Channel?, name: String) {
        channel?.exchangeDeclare("rabbitmq-demo", "topic", true)

        channel?.queueDeclare("event-number", true, false, false, null)
        channel?.queueBind("event-number", "rabbitmq-demo", "event.number", null)
    }
}

Let’s break down what this code does:

  1. Class Definition: RabbitMqBootstrap is a class that extends ChannelInitializer. This means it’s designed to initialize RabbitMQ resources related to communication channels.
  2. Event Handling: The class defines a function called onStartupEvent, which is annotated with @EventListener. This annotation indicates that this function should be triggered when a specific event occurs in the Micronaut application. In this case, it listens for the ServerStartupEvent.
  3. Channel Initialization: The initialize function overrides a method from the ChannelInitializer class. It’s responsible for configuring RabbitMQ resources.
    1. The exchangeDeclare method is used to declare an exchange named “rabbitmq-demo” of type “topic” with the durable flag set to true. This creates a topic exchange that is designed to route messages based on a routing key pattern.
    2. The queueDeclare method declares a queue named “event-number” with various configuration options, including making it durable.
    3. The queueBind method binds the “event-number” queue to the “rabbitmq-demo” exchange using the routing key “event.number.” This binding allows messages with the specified routing key to be routed to the queue.

Step 7: Triggering the publisher

You can create a controller and initiate the publisher to publish a message. Here we have used the controller from Rest API in Micronaut

    @Inject
    lateinit var publisher: Publisher
    @Get("/simple/{params}")
    suspend fun pathVariable(params: Long): Long? {
        publisher.emitEventNumber(params)
        log.error("This is a test error")
        return params
    }

After this change, you can trigger the controller using postman or web browser

Output

Code: Rabbit Mq Implementation in Micronaut

Related Post