RabbitMQ – Hello World

Good morning. In this post we will explore RabbitMQ by Pivotal. RabbitMQ is a message broker. Message brokers are considered middleware. Applications subscribe to a queue to send and receive messages. Another queue broker I have used in products is MSMQ from Microsoft. In this post we will only experiment with RabbitMQ. You may decide to use message queues to communicate between microservices.

For this post I decided to use Windows 10. With some minor changes regarding installation, the software written in Java should also work without modifications in Linux.

RabbitMQ is a message broker: it accepts and forwards messages. You can think about it as a post office: when you put the mail that you want posting in a post box, you can be sure that the postal carrier will eventually deliver the mail to your recipient. In this analogy, RabbitMQ is a post box, a post office and a postman.

Producing means nothing more than sending.  A program that sends messages is a producer.

A queue is the name for a post box which lives inside RabbitMQ.  Although messages flow through RabbitMQ and your applications, they can only be stored inside a queue.  A queue is only bound by the host’s memory & disk limits, it is essentially a large message buffer.  Many producers can send messages that go to one queue, and many consumers can try to receive data from one queue.

Consuming has a similar meaning to receiving.  A consumer is a program that mostly waits to receive messages.

Note that the producer, consumer, and broker do not have to reside on the same host; indeed in most applications they do not.  An application can be both a producer and consumer.

RabbitMQ speaks multiple protocols.  In this example we will use AMQP 0-9-1, which is an open, general-purpose protocol for messaging.  There are a number of clients for RabbitMQ in many different languages.  We will use the Java client provided by RabbitMQ.

The code in this post is the equivalent Hello World for many languages and products. We will write two simple applications. One will send a message using a queue. The second will read from the same queue the message.

Before writing any Java code we need to install the prerequisites for RabbitMQ. In my case I am running on a 64-bit machine. We need to download and install Erlang. Erlang is a general purpose, concurrent, functional programming language. To learn more about it you may read this post in Wikipedia.

I downloaded and installed Erlang in my computer using all the provided defaults. I installed it using the following information:

URL http://www.erlang.org/downloads
Download C:\temp\otp_win64_21.2.exe
Location C:\Program Files\erl10.2

After installing Erlang I restarted my machine.

To download and install RabbitMQ I used all the defaults provided by the installer and the following information:

URL https://www.rabbitmq.com/install-windows.html
Download c:\temp\rabbitmq-server-3.7.12.exe
Location C:\Program Files\RabbitMQ Server

After installing RabbitMQ I also restarted my computer.

Let’s take a look at the console output of the receiver:

   
C:\Temp>java -jar rabitt.jar recv
args.length: 1
s ==>recv<== [*] Waiting for messages. To exit press CTRL+C [x] Received ==>Hello World !!!<== [x] Received ==>Hello World !!!<== [x] Received ==>Hello World !!!<== Terminate batch job (Y/N)? y C:\Temp>

Note that we invoke a batch file. The same message “Hello World !!!” is received three times. We enter a ctrl-C and we are prompted to exit.

The associated sender output running on a different console follows:

C:\Temp>rabbit-send.bat

C:\Temp>java -jar rabitt.jar send
args.length: 1
s ==>send<== [x] Sent ==>Hello World !!!<== C:\Temp>
C:\Temp>rabbit-send.bat

C:\Temp>java -jar rabitt.jar send
args.length: 1
s ==>send<== [x] Sent ==>Hello World !!!<== C:\Temp>rabbit-send.bat

C:\Temp>java -jar rabitt.jar send
args.length: 1
s ==>send<== [x] Sent ==>Hello World !!!<== C:\Temp>

This is also a batch file. The batch file is invoked three times. Each time we send the same string “Hello World !!!”.

There are different ways to run a java JAR file on Windows. In this case we encapsulate the JAR we generate for both sender and receiver in their separate batch files. The batch file for the receiver follows:

java -jar rabbit.jar recv

The batch file for the sender follows:

java -jar rabbit.jar send

In the original source code I made a typo and used “rabitt” instead or “rabbit”. I believe all typos were addressed.

The code for the solution follows:

package com.canessa.rabbit;

public class Solution {

	public static void main(String[] args) throws Exception {

		// **** ****
		System.out.println("args.length: " + args.length);
		
		// **** ****
		for (String s : args) {
			
			// **** ****
			System.out.println("s ==>" + s + "<=="); // **** **** if (s.equals("send")) { Send send = new Send(); send.send(); } else if (s.equals("recv")) { Recv recv = new Recv(); recv.recv(); } else { System.out.println("unexpected s ==>" + s + "<==");
			}
		}
	}

}

In the main() method we pick up on the argument and decide to call the sender or the receiver.

The code for the receiver follows:

package com.canessa.rabbit;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;

public class Recv {

    private final static String QUEUE_NAME = "hello";

    public void recv() throws Exception {
    	
    	// **** ****
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        
        // **** ****
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        
        // **** ****
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        // **** ****
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            
            // **** ****
            System.out.println(" [x] Received ==>" + message + "<=="); }; channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
     }
}

We specify our computer and a queue named “hello”. We then wait for and display messages until we press control-C.

The code for the sender follows:

package com.canessa.rabbit;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class Send {

    private final static String QUEUE_NAME = "hello";

    public void send() throws Exception {
    	
    	// **** ****
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        
        // **** ****
        try (Connection connection = factory.newConnection();
        	Channel channel = connection.createChannel()) {
        	
        	// **** ****
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            String message = "Hello World !!!";
            channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
            
            // **** ****
            System.out.println(" [x] Sent ==>" + message + "<==");
        }
    }
}

In a similar fashion to the receiver, we also connect to the RabbitMQ server running on our Windows machine and use the “hello” queue. Please note that the RabbitMQ server must be up and running in order for the code to work. You may check this out using the following:

C:\Temp>net start
These Windows services are started:

   Adobe Acrobat Update Service
   Application Host Helper Service
   Application Information
   Background Tasks Infrastructure Service
   Base Filtering Engine
   Broadcom Management Agent
   Capability Access Manager Service
   Certificate Propagation
   Client License Service (ClipSVC)
   CNG Key Isolation
   COM+ Event System
   Computer Browser
   Connected Devices Platform Service
   Connected Devices Platform User Service_32aaf1
   Connected User Experiences and Telemetry
   CoreMessaging
   Credential Manager
   Cryptographic Services
   Data Usage
   DCOM Server Process Launcher
   Delivery Optimization
   Dell System Manager Service
   Device Association Service
   DHCP Client
   Diagnostic Policy Service
   Diagnostic Service Host
   Distributed Link Tracking Client
   DNS Client
   Extensible Authentication Protocol
   Function Discovery Resource Publication
   Geolocation Service
   IIS Admin Service
   IP Helper
   IPsec Policy Agent
   Local Session Manager
   Message Queuing
   MongoDB
   MySQL56
   Net.Msmq Listener Adapter
   Net.Pipe Listener Adapter
   Net.Tcp Listener Adapter
   Net.Tcp Port Sharing Service
   Network Connected Devices Auto-Setup
   Network Connection Broker
   Network List Service
   Network Location Awareness
   Network Store Interface Service
   NVIDIA Display Driver Service
   NVIDIA WMI Provider
   Offline Files
   Payments and NFC/SE Manager
   PDF Architect 3 Creator
   Plug and Play
   Power
   Print Spooler
   Program Compatibility Assistant Service
   Pulse Secure Network Service
   RabbitMQ     <=== shows the service is running
   Remote Access Connection Manager
   Remote Desktop Configuration
   Remote Desktop Services
   Remote Desktop Services UserMode Port Redirector
   Remote Procedure Call (RPC)
   RPC Endpoint Mapper
   Secure Socket Tunneling Protocol Service
   Security Accounts Manager
   Security Center
   Sentinel LDK License Manager
   Server
   Shell Hardware Detection
   ShrewSoft IKE Daemon
   ShrewSoft IPSEC Daemon
   Software Protection
   SQL Server (MSSQLSERVER)
   SQL Server Agent (MSSQLSERVER)
   SQL Server Browser
   SQL Server VSS Writer
   SSDP Discovery
   State Repository Service
   Storage Service
   Superfetch
   Sync Host_32aaf1
   System Event Notification Service
   System Events Broker
   System Guard Runtime Monitor Broker
   Task Scheduler
   TCP/IP NetBIOS Helper
   Themes
   Time Broker
   Touch Keyboard and Handwriting Panel Service
   Update Orchestrator Service
   User Manager
   User Profile Service
   WD Backup
   WD Drive Manager
   Web Account Manager
   Windows Audio
   Windows Audio Endpoint Builder
   Windows Connect Now - Config Registrar
   Windows Connection Manager
   Windows Defender Antivirus Network Inspection Service
   Windows Defender Antivirus Service
   Windows Defender Firewall
   Windows Defender Security Center Service
   Windows Event Log
   Windows Font Cache Service
   Windows License Manager Service
   Windows Management Instrumentation
   Windows Phone IP over USB Transport (IpOverUsbSvc)
   Windows Process Activation Service
   Windows Push Notifications System Service
   Windows Push Notifications User Service_32aaf1
   Windows Remediation Service
   Windows Search
   Windows Time
   WinHTTP Web Proxy Auto-Discovery Service
   Wired AutoConfig
   Workstation
   World Wide Web Publishing Service
   Xamarin Bonjour Service

The command completed successfully.

The code for the pom.xml file follows:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>RabbitMQHello</groupId>
  <artifactId>RabbitMQHello</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <build>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
    
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.7.0</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>      
      
    </plugins>
  </build>
  
  <dependencies>
  
  	<dependency>
  		<groupId>com.rabbitmq</groupId>
  		<artifactId>amqp-client</artifactId>
  		<version>5.5.1</version>
  	</dependency>
  	
	<dependency>
   		<groupId>org.slf4j</groupId>
   		<artifactId>slf4j-simple</artifactId>
   		<version>1.7.25</version>
	</dependency>
  	
  </dependencies>
  
</project>

The POM shows the two dependencies I used for the client and logging.

As I mentioned earlier, in a future post, I will be using RabbitMQ on a Linux platform to get some microservices talking to each other. Also, the code for this project is in my GitHub repository.

If you have comments or questions regarding this or any other post in this blog, or if you would like some help on a software development project, please feel free to contact me by leaving a message below. Your request will not be made public.

Keep on learning and having fun developing great software.

John

Follow me on Twitter:  @john_canessa

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.