<  Back to Blogs

Building Reliable Notification Systems with RabbitMQ and WebSockets

In today's world, real-time notifications are critical for many applications—whether it’s for live messaging, alert systems, or tracking updates. Building a reliable notification system requires managing message flow efficiently and ensuring real-time delivery across various clients. RabbitMQ, a robust message broker, and WebSockets, a protocol for two-way communication between the server and the client, provide a powerful combination for implementing such systems. This blog will walk you through how to build a reliable notification system using RabbitMQ as the message broker and WebSockets for real-time client communication.

Shashank KR

December 6, 2024

Why Use RabbitMQ and WebSockets for Notifications?

RabbitMQ:

RabbitMQ is an open-source message broker that supports various messaging protocols. It ensures reliable message delivery, persistence, and scalability, making it an excellent choice for handling notifications in distributed systems.

  • Message Durability: Messages are stored persistently on disk, ensuring they aren’t lost in case of server crashes.
  • Acknowledgments and Retries: RabbitMQ can track whether a message was successfully processed or needs to be retried.
  • Queueing and Routing: It allows fine control over how and where messages are routed, making it suitable for a variety of notification types.

WebSockets:

WebSockets provide full-duplex communication between a client and a server, making them ideal for real-time applications. Unlike traditional HTTP requests, WebSockets maintain an open connection, allowing instant delivery of messages.

  • Low Latency: WebSockets are designed for low-latency communication.
  • Real-Time Updates: Perfect for pushing real-time notifications without clients having to constantly poll the server.

Combining RabbitMQ for message management and WebSockets for real-time delivery ensures a reliable, efficient, and scalable notification system.

System Architecture Overview

The architecture of the notification system we will build can be broken down into the following components:

  1. Notification Producer: This part of the system sends notifications to RabbitMQ. It could be triggered by different events such as a user action, data changes, or external API events.
  2. RabbitMQ Broker: The message broker that manages the delivery of messages between producers and consumers.
  3. WebSocket Server: A server that listens for messages from RabbitMQ and delivers them in real-time to clients using WebSocket connections.
  4. Clients: The end-users or applications that receive the real-time notifications via WebSockets.

Step 1: Setting Up RabbitMQ

First, you’ll need to install and configure RabbitMQ. You can install it on your local machine or use a cloud-based RabbitMQ service like CloudAMQP.

# For Linux or MacOS:

sudo apt-get install rabbitmq-server

# Start RabbitMQ service

sudo service rabbitmq-server start

Once RabbitMQ is installed, you can access the management dashboard at http://localhost:15672/ (the default username/password is guest/guest).

RabbitMQ Exchange and Queue Configuration

To route messages effectively, we will set up an Exchange in RabbitMQ and bind it to one or more Queues. For example, you can create a "notifications" exchange, and each WebSocket client can subscribe to a unique queue to receive notifications intended for them.

// Node.js with amqplib for RabbitMQ

const amqp = require('amqplib');

// Connect to RabbitMQ server

const connectRabbitMQ = async () => {

  const connection = await amqp.connect('amqp://localhost');

  const channel = await connection.createChannel();

  // Create an exchange and queue

  await channel.assertExchange('notifications', 'fanout', { durable: false });

  const { queue } = await channel.assertQueue('', { exclusive: true });

  // Bind queue to exchange

  await channel.bindQueue(queue, 'notifications', '');

  return { connection, channel, queue };

};

Step 2: Setting Up the WebSocket Server

Next, we'll set up a WebSocket server using the ws package in Node.js.

npm install ws

We’ll create a WebSocket server that listens for new connections and sends notifications to clients in real time.

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

const clients = new Set();

// Handle WebSocket connections

wss.on('connection', (ws) => {

  clients.add(ws);

  ws.on('close', () => {

    clients.delete(ws);

  });

  // When a message is received

  ws.on('message', (message) => {

    console.log(`Received message: ${message}`);

  });

});

// Broadcast function to send notifications to all connected clients

const broadcast = (notification) => {

  clients.forEach((client) => {

    if (client.readyState === WebSocket.OPEN) {

      client.send(JSON.stringify(notification));

    }

  });

};

Step 3: Integrating RabbitMQ with WebSockets

Now that we have both RabbitMQ and WebSockets set up, we need to connect them. The WebSocket server will subscribe to the RabbitMQ exchange and receive notifications from the queue, which will then be sent to all connected clients.

Consuming Messages from RabbitMQ

We will set up a consumer that listens for messages from the RabbitMQ queue and broadcasts them to WebSocket clients.

const amqp = require('amqplib');

// Connect to RabbitMQ and listen for notifications

const consumeNotifications = async () => {

  const { channel, queue } = await connectRabbitMQ();

  // Listen for messages from RabbitMQ queue

  channel.consume(queue, (msg) => {

    const notification = msg.content.toString();

    console.log(`Received notification: ${notification}`);

    // Broadcast the notification to WebSocket clients

    broadcast(notification);

  }, { noAck: true });

};

// Start consuming messages from RabbitMQ

consumeNotifications();

Step 4: Sending Notifications

To complete the system, we need a way to produce notifications. This could be triggered by various events, such as a user action or a system alert.

// Function to send a notification to RabbitMQ

const sendNotification = async (message) => {

  const { channel } = await connectRabbitMQ();

  channel.publish('notifications', '', Buffer.from(message));

  console.log(`Sent notification: ${message}`);

};

// Example: Send a notification when an event occurs

sendNotification('User John has sent a message');

Step 5: Handling Message Acknowledgments and Reliability

RabbitMQ supports message acknowledgments, ensuring that messages are delivered reliably and not lost due to consumer failures. By default, RabbitMQ will consider a message successfully delivered as soon as it is sent to a consumer. However, you can implement manual acknowledgment to ensure that the message is processed correctly by the WebSocket server.

channel.consume(queue, (msg) => {

  const notification = msg.content.toString();

  try {

    broadcast(notification);

    channel.ack(msg);  // Acknowledge message after successful broadcast

  } catch (err) {

    channel.nack(msg); // Requeue message if an error occurs

  }

});

Conclusion

By combining RabbitMQ and WebSockets, you can build a reliable, scalable notification system capable of handling real-time updates efficiently. RabbitMQ ensures message durability and routing flexibility, while WebSockets enable low-latency, real-time communication with connected clients.

This approach is highly scalable, making it suitable for a wide range of applications—from messaging platforms to real-time tracking and alert systems. You can easily extend this solution with additional features such as user-specific queues, message retries, and analytics tracking.

address
205, 2nd floor, JSA Towers, Paramahansa Yogananda Rd, Indira Nagar 1st Stage, Hoysala Nagar, Indiranagar, Bengaluru, Karnataka 560038
© 2019 All Rights Reserved
© 2019 All Rights Reserved