Overview
Modern chat applications demand reliability, low latency, and real-time delivery. A client requested a chat system that could handle high concurrency while ensuring no message is lost, even in cases of server crashes or network interruptions.
The goal was to integrate a message queue (RabbitMQ) into the chat workflow, ensuring data durability and real-time delivery via Socket.IO, while also supporting media, contact sharing, and reply threads.
Challenge
- Data Loss Risk: Traditional Socket.IO emits could fail if the server crashes or restarts.
- High Concurrency: Chat rooms may have hundreds of users active simultaneously.
- Media Support: Messages could include images or contact cards, not just text.
- Scalable Architecture: The system should support horizontal scaling with multiple server instances.
Solution
The architecture combines Node.js, MongoDB, RabbitMQ, and Socket.IO:
-
Message Creation:
- Client sends a message with text, images, or contact info.
- The server validates and prepares the message payload.
-
Queue Integration:
- Messages are published to a durable RabbitMQ queue, ensuring they are not lost.
- Consumers can process messages for analytics, archiving, or further distribution.
-
Database Persistence:
- Messages are stored in MongoDB with metadata including reply references, timestamps, and linked status.
-
Real-Time Delivery:
- Socket.IO emits the message to all room participants.
- Last message preview in the room is updated for all members.
-
Message Flexibility:
- Supports text, images, and contacts seamlessly.
- Detects URLs automatically for link previews.
Implementation Highlights
export const createMessage = async (req: Request, res: Response) => {
const roomId = get(req, 'params.id', '');
const userId = get(req, 'user._id', '');
const text = get(req, 'body.text', '');
const images = get(req, 'body.images', []);
const contact = get(req, 'body.contact', null);
const messageType = get(req, 'body.messageType', '');
const lastMessage: any = images.length > 0
? { value: get(last(images), 'filename'), type: 'media' }
: { value: text, type: 'text' };
const room = await Room.findOne({ _id: roomId });
const roomMembers = get(room, 'members', []).map((m: any) => m.userId);
await Room.updateOne({ _id: roomId }, { lastMessage, lastMessageVisibleOnUsers: roomMembers });
const dateNow = momentTimezone.tz(moment(), 'Asia/Hong_Kong').toDate();
const newMessage = new Message({
text,
message_type: messageType,
media: images,
created_by: userId,
room: roomId,
created_at: dateNow,
updated_at: dateNow,
seen_by: [],
contact,
});
try {
// Save message to MongoDB
const savedMessage = await newMessage.save();
// Publish message to RabbitMQ
const payload = { ...savedMessage.toObject() };
await channel.assertQueue('chat_messages', { durable: true });
channel.sendToQueue('chat_messages', Buffer.from(JSON.stringify(payload)), { persistent: true });
// Emit to Socket.IO clients
let lastMessageText = text;
if (images[0]) lastMessageText = images[0].type;
if (contact) lastMessageText = 'contact';
ioContainer.io?.to(roomId).emit('NEW_MESSAGE', {
senderId: userId,
roomId,
text: lastMessageText,
data: savedMessage,
});
return res.status(200).json({ status: 'success', data: savedMessage });
} catch (error) {
return res.status(400).json({ status: 'error', error });
}
};Outcome
- Zero Message Loss: Integration with RabbitMQ guarantees durable messaging even if the server crashes.
- Real-Time Delivery: Socket.IO ensures all participants see messages instantly.
- Supports Multiple Message Types: Text, images, and contact messages handled seamlessly.
- Horizontal Scalability: Multiple server instances can process messages from the queue.
- Reliable Metadata: Timestamps and message status are consistent across clients and the database.
Conclusion
By integrating RabbitMQ with Socket.IO and MongoDB, the chat system became highly reliable, fault-tolerant, and scalable.
This approach ensures that messages are never lost, even under high load or unexpected failures, while maintaining real-time interactivity for users.
It demonstrates how combining message queues, persistent storage, and real-time protocols can build a modern, robust chat infrastructure ready for enterprise-scale applications.
Read more
Reliable Chat Messaging with RabbitMQ Integration
Implemented a robust chat system that leverages RabbitMQ for message durability and real-time delivery with Socket.IO.
Automating EC2 & JupyterHub Provisioning: Reducing Deployment Time from Hours to Minutes
A senior-engineer case study on converting a manual AWS provisioning workflow into a fully automated system using AWS SDK, IAM, S3, and EC2 orchestration.
Architecting a Scalable Learning Management Platform with React, Node.js, and AWS
A case study on migrating a monolithic LMS to a modular, microservices-inspired architecture with high scalability, real-time analytics, and multi-role support.