Micronaut Nats

Integration between Micronaut and nats.io

Version:

1 Introduction

This project includes integration between Micronaut and nats.io. The standard Java Client is used to do the actual publishing and consuming.

Release History

1.0.0

  • Micronaut 1.2.x minimum version

  • Basic support for consumer and producers

  • RPC feature

  • Queue feature

2 NATS Quick Start

To add support for NATS.io to an existing project, you should first add the Micronaut NATS configuration to your build configuration. For example:

implementation("io.micronaut.nats:micronaut-nats")
<dependency>
    <groupId>io.micronaut.nats</groupId>
    <artifactId>micronaut-nats</artifactId>
</dependency>

Configuring NATS

Without any configuration the defaults in the Options will be used.

It is possible to configure multiple connections to the same server, different servers, or a single connection to one of a list of servers.

nats:
    server1:
      addresses:
        - "nats://localhost:4222"
      username: guest
      password: guest
    server2:
      addresses:
        - "nats://randomServer:4222"
      username: guest
      password: guest

NATS also supports a fail over connection strategy where the first server that connects successfully will be used among a list of servers. To use this option in Micronaut, simply supply a list of host:port addresses.

nats:
    addresses:
      - "nats://localhost:4222"
      - "nats://randomServer:4222"
    username: guest
    password: guest
When the configuration option nats.servers is used, no other options underneath nats are read; for example nats.username.
It is also possible to disable the integration entirely with nats.enabled: false

Creating a NATS Producer with @NatsClient

To create a NATS Producer that sends messages you can simply define an interface that is annotated with @NatsClient.

For example the following is a trivial @NatsClient interface:

ProductClient.java
import io.micronaut.nats.annotation.NatsClient;
import io.micronaut.nats.annotation.Subject;
import io.micronaut.messaging.annotation.Body;

@NatsClient (1)
public interface ProductClient {

    @Subject("my-products") (2)
    void send(String name);

    void sendProduct(@Subject String brand, @Body String name); (3)
}
1 The @NatsClient annotation is used to designate this interface as a client
2 The @Subject annotation indicates which subject the Message should be published to
3 It is also possible for the subject to be dynamic by making it a method argument

At compile time Micronaut will produce an implementation of the above interface. You can retrieve an instance of ProductClient either by looking up the bean from the ApplicationContext or by injecting the bean with @Inject:

Using ProductClient
ProductClient client = applicationContext.getBean(ProductClient.class);
client.sendProduct("Nike", "Blue Trainers");

Creating a NATS Consumer with @NatsListener

To listen to NATS messages you can use the @NatsListener annotation to define a message listener.

The following example will listen for messages published by the ProductClient in the previous section:

ProductListener.java
import io.micronaut.messaging.annotation.Body;
import io.micronaut.nats.annotation.NatsListener;
import io.micronaut.nats.annotation.Subject;

@NatsListener (1)
public class ProductListener {

    @Subject("my-products") (2)
    public void receive(@Body String name) { (3)
        System.out.println("Got Product - " + name);
    }
}
1 The @NatsListener is used to designate this class as a listener.
2 The @Subject annotation is again used to indicate which subject to subscribe to.
3 The receive method defines one argument, which will receive the value.

3 NATS Producers Using @NatsClient

The example in the quick start presented a trivial definition of an interface that be implemented automatically for you using the @NatsClient annotation.

The implementation that powers @NatsClient (defined by the NatsIntroductionAdvice class) is, however, very flexible and offers a range of options for defining Kafka clients.

3.1 Defining @NatsClient Methods

All methods that publish messages to NATS must meet the following conditions:

  • The method must reside in a interface annotated with @NatsClient.

  • The method or a method parameter must be annotated with @Subject.

  • The method must contain an argument representing the body of the message.

In order for all of the functionality to work as designed in this guide your classes must be compiled with the parameters flag set to true. If your application was created with the Micronaut CLI, then that has already been configured for you.

Simple Producer

The easiest way for defining a producer is the following:

@Subject("my-products")
void sendProduct(String name);

Dynamic subject

void sendProduct(@Subject String topic, String name);

Publishing to Queues

The NATS server will route the message to the queue and select a message receiver.

Return Type and RPC

If the producer defines a return type, it automatically will use the RPC logic and will wait for an answer from a consumer
@Subject("product")
Product sendProduct(String name);

@Subject("product")
Single<Product> sendProduct(String name);

@Subject("product")
Maybe<Product> sendProduct(String name);

@Subject("product")
Flowable<Product> sendProduct(String name);

4 NATS Consumers Using @NatsListener

The quick start section presented a trivial example of what is possible with the @NatsListener annotation.

The implementation that powers @NatsListener (defined by the NatsConsumerAdvice class) is, however, very flexible and offers a range of options for consuming NATS message.

4.1 Defining @NatsListener Methods

All methods that consume messages from NATS must meet the following conditions:

  • The method must reside in a class annotated with @NatsListener.

  • The method must be annotated with @Subject.

In order for all of the functionality to work as designed in this guide your classes must be compiled with the parameters flag set to true. If your application was created with the Micronaut CLI, then that has already been configured for you.

Simple Consumer

The easiest way for defining a producer is the following:

    @Subject("my-products")
    public void receive(String name) {
        System.out.println("Got Product - " + name);
    }

Queue Support

Subscribers may specify queue groups at subscription time. When a message is published to the group NATS will deliver it to a one-and-only-one subscriber.

Queue groups do not persist messages. If no listeners are available, the message is discarded.
    @Subject(value = "my-products", queue="my-queue")
    public void receive(String name) {
        System.out.println("Got Product - " + name);
    }

Return Type and RPC

If the consumer defines a return type, it automatically will use the RPC logic and will send the return value to the producer
    @Subject(value = "my-products")
    public Product receive(String name) {
        return new Product(name);
    }

5 NATS Health Indicator

This library comes with a health indicator for applications that are using the management module in Micronaut. See the Health Endpoint documentation for more information about the endpoint itself.

The information reported from the health indicator is under the nats key.

"nats": {
  "status": "UP",
  "details": {
    "servers": ["nats://localhost:4222"]
  }
}
To disable the NATS health indicator entirely, add endpoints.health.nats.enabled: false.