Hot questions for Using RabbitMQ in microservices

Top Java Programmings / RabbitMQ / microservices

Question:

Assume I have this definition for Sink Interface

public interface Sink {
  @Input("input")
  SubscribableChannel input();

  @Input("anotherInput")
  SubscribableChannel anotherInput();
}

and the following controller is bound to RabbitMQ (all set correctly according to Spring Cloud Stream Binder Rabbit)

@Controller
@EnableBinding(Sink.class)
public class InputMessageController {

    @StreamListener("input")
    public void handle(String message) {
        System.out.println("Received from input: " + message);
    }

    @StreamListener("anotherInput")
    public void handleOther(String message) {
        System.out.println("Received from another input: " + message);
    }

Although it works, but it's bad code because of duplicates etc.

I'd like to habe one handler in this controller which listens, in another word subscribes to both channels in Sink Interface and handles both of them based on some conditions for example. So far I couldn't figure it out with standard @StreamListener annotation, since it apparently does not accept an array of String (channel names)

My goal is sth like this:

@Controller
@EnableBinding(Sink.class)
public class InputMessageController {

    @StreamListener("input", "anotherInput")
    public void handle(String message) {
        System.out.println("Received " + message + "from " +
                   ((/*some condition*/) ? "1st" : "2nd") + " input");
    }

I'd appreciate any idea to solve it clean or explanation about Spring Cloud Stream API!


Answer:

Annotate your class with Rabbitlistener and declare your queues as argument, then annotate a method with Rabbithandler. This method receives inputs for all declared queues.

@Controller
@EnableBinding(Sink.class)
@RabbitListener(queues = {"input", "anotherInput"})
public class InputMessageController {

    @RabbitHandler
    public void handle(String message) {
        System.out.println("Received " + message + "from " +
                   ((/*some condition*/) ? "1st" : "2nd") + " input");
    }

Question:

I'm building an application that consists out of several microservices. One of the microservices, which is called Hera, manages users. Another microservice manages authorization and authentication. This microservice is called Zeus and is an implementation of Spring OAuth 2.0.

When a user is created, updated or deleted in Hera, I'd like to replicate certain information to Zeus via RabbitMQ. This information includes the username, the user type (an enum) and a flag to indicate whether the user is enabled.

I've already set up RabbitMQ and everything is working properly. The only thing I'm not certain about is the message body content. How should this information be packaged in the message? For instance, should I create a maven project containing the POJO with the required properties which will be marshalled and send via RabbitMQ and add dependency to this project in both Hera and Zeus? Or should I just add this information as a list of plain properties?

I could not find any best practices or guidelines on this subject, so I'm asking you.

Thank you in advance!


Answer:

I would use common library for DTOs but you need to have serialization which is tolerant and allows version differences e.g. handle added/removed fields or a change of data types. If you share code you have to allow for the code to be running different a version in each service so that when you upgrade one service you are not forced to update any other.

Question:

I have a question searching for the best approach of solving a problem. We are currently working on replacing our software monolith by a microservice architecture.

We want to use a message queue as communication between the different microservices.

One of our microservice (the mail service) need to react after he has received two messages from two several microservices. The first message gives information about an order that has been made. It provides info about email content and recipients, the second message provides link to attachments, the email should include.

The mail service should wait until both messages are received. Currently i am planning to store all messages into the database (one table for each message) and check every 5 seconds if both info is existing and the email can be send.

But I have the feeling that maybe RabbitMQ also offers an approach, so I do not need to make my own development to avoid that race condition between those two messages.

What would be your approach to solve this?


Answer:

I would change the message pattern so that you have three messages;

  1. First message is published containing order information. The outcome of this message being consumed is a second message being published containing additional information.

  2. Second message containing the additional information is processed and the information persisted. This is where you publish the third message.

  3. The third and final message acts as a notification to say "hey, I now have everything needed to actually send the email".

This way you don't have to check a database every x seconds and you can extended the message workflow rather cheaply.

Hope that helps :)