Tutorials

Build a Real-Time Chat Application with Serverless Redis

In this tutorial, we will build a real-time chat application using Flask and SocketIO, leveraging Upstash Redis for efficient message handling. Redis, being a fast, in-memory data store, provides an ideal backbone for real-time messaging systems due to its low latency and support for Pub/Sub messaging patterns.

Why Upstash Redis?

  • Scalability: Handles large volumes of messages with minimal latency.
  • Simplicity: Easy to set up with minimal configuration.
  • Cost-Efficiency: Serverless model reduces operational costs.

Setup

1. Install the Required Libraries

Install Flask, Flask-SocketIO, and the Redis library by running:

pip install flask flask-socketio redis

2. Create a Redis Database

Create a Redis database using the Upstash Console or Upstash CLI.

Create a .env file in the root of your project with the following content:

UPSTASH_REDIS_HOST=your_upstash_redis_hostUPSTASH_REDIS_PORT=your_upstash_redis_portUPSTASH_REDIS_PASSWORD=your_upstash_redis_password

Code

Now, it's time to implement the chat application. We'll create a Flask server that uses SocketIO for real-time communication. We'll also configure the server to use Upstash Redis as the message queue.

We need to use the rediss:// protocol instead of redis:// to connect to Redis over TLS. This ensures secure communication between the server and the Redis instance.

main.py
from flask import Flask, render_templatefrom flask_socketio import SocketIOimport os# Initialize Flask appapp = Flask(__name__)app.config["SECRET_KEY"] = os.getenv("SECRET_KEY", os.urandom(24))# Set up Redis URL with TLSredis_password = os.getenv('UPSTASH_REDIS_PASSWORD')redis_host = os.getenv('UPSTASH_REDIS_HOST')redis_port = int(os.getenv('UPSTASH_REDIS_PORT', 6379))redis_url = f"rediss://:{redis_password}@{redis_host}:{redis_port}"# Initialize SocketIO with Redis message queuesocketio = SocketIO(app, message_queue=redis_url, cors_allowed_origins="*")# WebSocket handlers@socketio.on("connect")def handle_connect():    print("Client connected.")@socketio.on("disconnect")def handle_disconnect():    print("Client disconnected.")@socketio.on("message")def handle_message(data):    """Handle incoming chat messages."""    print(f"Message received: {data}")    # Broadcast the message to all connected clients except the sender    socketio.emit("message", data, include_self=False)# Serve the chat HTML page@app.route("/")def index():    return render_template("chat.html")  # Render the chat interface templateif __name__ == "__main__":    socketio.run(app, debug=True, host="0.0.0.0", port=8000)

Code Explanation

  • We initialized a Flask app and set a secret key for session management.
  • We set up the Redis URL with TLS for secure communication.
  • We initialize a SocketIO instance with the Flask app and configure it to use Redis as the message queue.
  • We define WebSocket event handlers for connect, disconnect, and message events.
  • The handle_message function broadcasts the received message to all connected clients except the sender.
  • We define a route to serve the chat interface template.

Now let's create a template for the chat interface. We're not going to go into the details of the HTML and CSS, as the focus is on the real-time messaging functionality.

chat.html
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Real-Time Chat</title>    <script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>    <style>        body {            font-family: Arial, sans-serif;            margin: 0;            padding: 0;            display: flex;            flex-direction: column;            align-items: center;            justify-content: center;            height: 100vh;            background-color: #f4f6f9;        }        #chat-container {            width: 90%;            max-width: 600px;            height: 70%;            border: 1px solid #ddd;            border-radius: 10px;            background-color: #fff;            display: flex;            flex-direction: column;            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);        }        #chat-box {            flex: 1;            overflow-y: auto;            padding: 15px;            border-bottom: 1px solid #ddd;            scrollbar-width: thin;            scrollbar-color: #ccc #f4f6f9;        }        #chat-box::-webkit-scrollbar {            width: 8px;        }        #chat-box::-webkit-scrollbar-thumb {            background: #ccc;            border-radius: 5px;        }        .message {            margin: 10px 0;            padding: 10px 15px;            border-radius: 15px;            max-width: 70%;            word-wrap: break-word;        }        .message.sent {            align-self: flex-end;            background-color: #007BFF;            color: white;        }        .message.received {            align-self: flex-start;            background-color: #f1f1f1;            color: black;        }        #input-container {            display: flex;            padding: 10px;            gap: 10px;            background-color: #f4f6f9;            border-radius: 0 0 10px 10px;        }        #message-input {            flex: 1;            padding: 10px;            font-size: 16px;            border: 1px solid #ccc;            border-radius: 5px;        }        #send-button {            padding: 10px 20px;            font-size: 16px;            border: none;            border-radius: 5px;            background-color: #007BFF;            color: white;            cursor: pointer;            transition: background-color 0.3s ease;        }        #send-button:hover {            background-color: #0056b3;        }    </style></head><body>    <div id="chat-container">        <div id="chat-box"></div>        <div id="input-container">            <input id="message-input" type="text" placeholder="Type your message...">            <button id="send-button">Send</button>        </div>    </div>    <script>        const socket = io();        const chatBox = document.getElementById("chat-box");        const messageInput = document.getElementById("message-input");        const sendButton = document.getElementById("send-button");        // Generate or retrieve a random username for this tab        function getUsername() {            let username = sessionStorage.getItem("username");            if (!username) {                username = "User" + Math.floor(Math.random() * 1000); // Temporary random username                sessionStorage.setItem("username", username);            }            return username;        }        const username = getUsername();        // Append message to chat box        function addMessage(message, type = "received") {            const messageElement = document.createElement("div");            messageElement.textContent = message;            messageElement.classList.add("message", type);            chatBox.appendChild(messageElement);            chatBox.scrollTop = chatBox.scrollHeight;        }        // Receive messages from server        socket.on("message", (data) => {            addMessage(`${data.user}: ${data.message}`, "received");        });        // Send message to server        sendButton.addEventListener("click", () => {            const message = messageInput.value.trim();            if (message) {                addMessage(`You: ${message}`, "sent");                socket.emit("message", { user: username, message });                messageInput.value = "";            }        });        // Optional: Press Enter to send a message        messageInput.addEventListener("keypress", (e) => {            if (e.key === "Enter") {                sendButton.click();            }        });    </script></body></html>

Running the Application

  1. Start the server:
    python app.py
  2. Open your web browser and go to http://localhost:8000/.

You should see the chat interface. You can send and recieve messages in real-time. Just open the same URL in multiple tabs or browsers to simulate multiple users chatting with each other.


Conclusion

In this tutorial, we built a real-time chat application using Flask, SocketIO, and Upstash Redis. Redis, with its low latency and high throughput, is an ideal choice for real-time messaging systems.

To learn more about Upstash Redis, visit the Upstash Redis Documentation.

Loading search…