Skip to content

Instantly share code, notes, and snippets.

@maanimis
Created February 15, 2025 18:35
Show Gist options
  • Save maanimis/e28da90f5bb3d09833bc7e0af648e1b5 to your computer and use it in GitHub Desktop.
Save maanimis/e28da90f5bb3d09833bc7e0af648e1b5 to your computer and use it in GitHub Desktop.
The code enables real-time WebSocket messaging with Redis Pub/Sub.

From chatgpt

To implement WebSockets with Redis Pub/Sub for scalable, real-time communication across multiple servers, here’s a step-by-step example that combines WebSockets and Redis.

Architecture

  • WebSocket: Handles real-time communication between clients and the server.
  • Redis Pub/Sub: Allows the server to broadcast messages to all connected WebSocket clients, even when there are multiple instances of the server.

1️⃣ Install Dependencies

First, you need to install the required packages:

npm install express ws redis
  • express: For setting up the web server.
  • ws: For WebSocket handling.
  • redis: For Redis Pub/Sub integration.

2️⃣ Create .env File

Store your Redis configuration in a .env file:

REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_CHANNEL=chat_channel
PORT=3000

3️⃣ WebSocket Server with Redis Pub/Sub

Now, let’s set up the WebSocket server along with Redis Pub/Sub integration:

require("dotenv").config();
const express = require("express");
const WebSocket = require("ws");
const redis = require("redis");

const app = express();
const server = app.listen(process.env.PORT || 3000, () => {
    console.log(`🚀 Server running on http://localhost:${process.env.PORT || 3000}`);
});

// Set up WebSocket server
const wss = new WebSocket.Server({ server });

// Redis setup (Publisher)
const redisClient = redis.createClient({
    host: process.env.REDIS_HOST,
    port: process.env.REDIS_PORT,
});

// Redis setup (Subscriber)
const redisSubscriber = redis.createClient({
    host: process.env.REDIS_HOST,
    port: process.env.REDIS_PORT,
});

// Listen to Redis Pub/Sub channel
redisSubscriber.subscribe(process.env.REDIS_CHANNEL);

// Handle WebSocket connections
wss.on("connection", (ws) => {
    console.log("✅ New WebSocket client connected.");

    // Listen for incoming WebSocket messages and publish them to Redis
    ws.on("message", (message) => {
        console.log("📩 Message received from WebSocket client:", message);

        // Publish the message to Redis channel
        redisClient.publish(process.env.REDIS_CHANNEL, message);
    });

    // Send a welcome message to the WebSocket client
    ws.send(JSON.stringify({ message: "Welcome to the WebSocket server!" }));

    // Handle WebSocket errors
    ws.on("error", (error) => {
        console.error("❌ WebSocket error:", error);
    });
});

// Handle Redis messages and broadcast them to all connected WebSocket clients
redisSubscriber.on("message", (channel, message) => {
    console.log(`📡 New message on Redis channel '${channel}':`, message);

    // Broadcast the message to all connected WebSocket clients
    wss.clients.forEach((client) => {
        if (client.readyState === WebSocket.OPEN) {
            client.send(message);
        }
    });
});

console.log("✅ Redis Pub/Sub is set up.");

4️⃣ Frontend: WebSocket Client

Create a simple HTML page that connects to the WebSocket server and listens for messages:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebSocket Chat</title>
</head>
<body>
    <h1>WebSocket Chat</h1>
    <div id="messages"></div>
    <input type="text" id="messageInput" placeholder="Type a message..." />
    <button id="sendButton">Send</button>

    <script>
        const socket = new WebSocket("ws://localhost:3000");
        const messagesDiv = document.getElementById("messages");
        const messageInput = document.getElementById("messageInput");
        const sendButton = document.getElementById("sendButton");

        // On connection open, show welcome message
        socket.onopen = () => {
            console.log("✅ WebSocket connection established.");
        };

        // Listen for incoming WebSocket messages
        socket.onmessage = (event) => {
            const data = JSON.parse(event.data);
            const messageElement = document.createElement("p");
            messageElement.textContent = data.message;
            messagesDiv.appendChild(messageElement);
        };

        // Send a message when the user clicks "Send"
        sendButton.addEventListener("click", () => {
            const message = messageInput.value;
            if (message) {
                socket.send(message);
                messageInput.value = ""; // Clear input
            }
        });

        // Handle WebSocket errors
        socket.onerror = (error) => {
            console.error("❌ WebSocket error:", error);
        };
    </script>
</body>
</html>

5️⃣ Run Redis Server

Make sure Redis is running:

docker run -d --name redis -p 6379:6379 redis

If you don’t have Redis installed, you can use Docker to run it or install it locally.


6️⃣ Running the WebSocket Server

To run the WebSocket server:

node server.js

7️⃣ Test the WebSocket Chat

  1. Open the Frontend: Open index.html in your browser.
  2. Test Messaging: Type a message and click Send. Your message will be sent to the WebSocket server and broadcast to all connected clients through Redis Pub/Sub.

🔑 Key Concepts:

  1. WebSocket Server: Handles real-time communication with the clients.
  2. Redis Pub/Sub:
    • The publisher (in the WebSocket server) sends messages to a Redis channel.
    • The subscriber (also in the WebSocket server) listens for messages on the Redis channel and broadcasts them to all WebSocket clients.
  3. Scaling: With this setup, even if the server is scaled across multiple instances, Redis Pub/Sub ensures that all instances can publish and subscribe to the same channel, making the system scalable.

🎯 Conclusion

This setup is highly scalable and can handle massive-scale real-time events using WebSockets combined with Redis Pub/Sub. The WebSocket server and clients can send and receive real-time messages, while Redis ensures messages are broadcast across multiple instances of the WebSocket server. This approach is ideal for building chat apps, live notifications, and any other event-driven systems.

Let me know if you'd like more improvements or explanations! 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment