Introduction

Handling real-time events efficiently is crucial in any social media-like application. In CampusX, I implemented Redis Pub/Sub to manage like notifications seamlessly. This approach ensures that when a user likes a post, the owner of the post receives an instant notification via WebSockets.

This blog will break down how Redis Pub/Sub works and how it powers the real-time like notifications in CampusX.


What is Redis Pub/Sub?

Redis Pub/Sub (Publish/Subscribe) is a messaging system where publishers send messages to specific channels, and subscribers listening to those channels receive the messages instantly. Unlike traditional message queues, Redis Pub/Sub does not store messages. Once a message is delivered to all subscribers, it disappears from memory.

Key Components:

  • Publisher: Sends messages to a Redis channel.
  • Subscriber: Listens for messages on a channel.
  • Channel: A topic where messages are broadcasted.

Setting Up Redis Pub/Sub for Like Notifications in CampusX

1️⃣ Configuring Redis Client

First, I created a Redis configuration file (redis.js) to manage the publisher and subscriber connections:

import { createClient } from "redis";

const pub = createClient();
const sub = createClient();

pub.on("error", (err) => console.error("❌ Redis Publisher Error:", err));
sub.on("error", (err) => console.error("❌ Redis Subscriber Error:", err));

async function connectRedis() {
  try {
    await pub.connect();
    console.log("✅ Redis Publisher Connected");
    await sub.connect();
    console.log("✅ Redis Subscriber Connected");
  } catch (err) {
    console.error("❌ Redis Connection Error:", err);
  }
}

connectRedis();

export { pub, sub };

This ensures that both the publisher and subscriber are connected when the backend starts.


2️⃣ Publishing Like Events

Whenever a user likes a post, the backend publishes a message on the like_status channel:

import { pub } from "../config/redis.js";

async function publishLikeStatus(status, postOwnerId, userId) {
  console.log("Published Like Status");

  if (!pub.isReady) {
    console.log("🟡 Connecting Redis Publisher...");
    await pub.connect();
  }

  try {
    await pub.publish(
      "like_status",
      JSON.stringify({ status, postOwnerId, userId })
    );
    console.log("✅ Like status published successfully");
  } catch (err) {
    console.error("❌ Error publishing like status:", err);
  }
}

export default publishLikeStatus;

This function takes in the like status, the owner of the post, and the user who liked the post. It then publishes this information on Redis for subscribers to pick up.


3️⃣ Subscribing to Like Events

The backend subscribes to the like_status channel to listen for new like events and sends notifications via WebSockets:

import { sub } from "../config/redis.js";

const subscribeLikeStatus = async (io, userSockets) => {
  sub.on("error", (err) => console.error("❌ Redis Subscriber Error:", err));

  if (!sub.isReady) {
    console.log("🟡 Connecting Redis subscriber...");
    await sub.connect();
  }

  try {
    await sub.subscribe("like_status", (message) => {
      console.log("📩 Message received:", message);
      const data = JSON.parse(message);
      console.log("📌 Data received:", data);

      // Check if the post owner is online
      const ownerSocketId = userSockets.get(data.postOwnerId);
      console.log("📡 Owner Socket ID:", ownerSocketId);

      if (ownerSocketId) {
        io.to(ownerSocketId).emit("like_status", data);
        console.log("📤 Sent like notification to:", ownerSocketId);
      } else {
        console.log("⚠️ Post owner not online:", data.postOwnerId);
      }
    });

    console.log("✅ Subscribed to 'like_status' channel.");
  } catch (err) {
    console.error("❌ Redis subscription error:", err);
  }
};

export { subscribeLikeStatus };

This function listens for new messages and checks if the post owner is online. If they are, it sends a WebSocket event notifying them of the new like.


4️⃣ WebSocket Integration

I integrated WebSockets to track connected users and send real-time notifications:

const userSockets = new Map();

const connectWebSocket = (server) => {
  const io = new Server(server, {
    cors: { origin: "*" },
  });

  io.on("connection", (socket) => {
    console.log("Client connected:", socket.id);

    socket.on("register", (userId) => {
      console.log("🔹 User registered(ID):", userId, "Socket ID:", socket.id);
      userSockets.set(userId, socket.id);
      socket.userId = userId;
    });

    socket.on("disconnect", () => {
      if (socket.userId) {
        userSockets.delete(socket.userId);
        console.log("🔻 User disconnected:", socket.userId);
      }
      console.log("Client disconnected:", socket.id);
    });
  });

  return io;
};

export { connectWebSocket, userSockets };

This keeps track of online users and cleans up the memory when users disconnect.


How It Works End-to-End

1️⃣ A user likes a post, triggering publishLikeStatus.

2️⃣ Redis receives the message and delivers it to all subscribers.

3️⃣ subscribeLikeStatus processes the message and checks if the post owner is online.

4️⃣ If online, the notification is sent via WebSockets.

5️⃣ The frontend receives the WebSocket event and displays a toast notification.


Why Use Redis Pub/Sub?

Fast & Lightweight – Delivers messages instantly without storing them.

Decoupled Architecture – Publishers and subscribers don’t need direct knowledge of each other.

Scalability – Supports multiple subscribers across different backend services.


Conclusion

By integrating Redis Pub/Sub, CampusX efficiently handles real-time like notifications without overloading the database. This architecture ensures that users receive instant updates while keeping the system scalable and responsive.

If you're building a real-time application, consider Redis Pub/Sub for event-driven communication. 🚀