Real time messaging with Centrifugo

Introduction

At Zen8Labs, we handle a diverse range of projects. This includes creating new systems from the ground up as well as enhancing existing ones. We are versatile in our approach: sometimes we design solutions based on our own ideas, and other times we adhere to our clients’ specifications. A common challenge we encounter is integrating new features into an existing system, especially when they don’t seamlessly align with the current framework. Today, we’re excited to share a specific project we’ve been working on, developing a chat service using a Python/Django backend. 

To begin, let’s discuss why Python/Django might not be the best fit for this type of system: 

  1. Asynchronous Handling: Django, traditionally a synchronous framework, is not inherently built for handling real-time, asynchronous tasks efficiently. Real time messaging requires a persistent, open connection to the server, which is beyond Django’s conventional request-response cycle. 
  1. Concurrency: Handling multiple concurrent connections in real-time is challenging with Django alone, as its architecture is not optimized for this kind of workload. 
  1. WebSocket’s Support: Prior to Django 3.0, there was no built-in support for WebSocket’s, a key technology for real-time messaging. While newer versions and channels offer this support, integrating this functionality is way too complex and resource intensive. 

As we can see, Django excels as a web-based framework for building robust and secure web applications. It falls short in dealing with real-time communication and high concurrency, which are crucial for a chat service. 

This is where Centrifugo comes in, filling the gap with its efficient handling of real-time messaging, scalability, and ease of integration. It makes the combination of Django and Centrifugo an excellent choice for developing real-time chat applications. 

Centrifugo is an open-source scalable real-time messaging, it is a server language-agnostic and can be used to build chat apps, live comments, multiplayer games, real-time data visualizations, collaborative tools, etc., in combination with any backend. Centrifugo is well suited for modern architectures and allows decoupling of business logic from the real-time transport layer. 

Centrifugo significantly eases our workload in managing WebSocket systems by handling most of the complex tasks: 

Handling Persistent Connections

  • Scalability: Centrifugo is designed to handle thousands to millions of persistent WebSocket connections. This is a significant challenge in real-time applications, where each active user requires a continuous connection to the server. 
  • Resource Management: It efficiently manages the resources and keeps the overhead low. Ensuring that the server can maintain numerous simultaneous connections without significant degradation in performance.

Real Time Data Transmission

  • Bi-Directional Communication: WebSocket provides a full-duplex communication channel, allowing data to be sent and received simultaneously. Centrifugo leverages this to ensure real-time data transmission, crucial for chat applications. 
  • Efficient Message Routing: Centrifugo efficiently routes messages to the correct recipients in real-time, which can be complex. Especially, when dealing with a large number of users and channels. 

Connection Stability and Management

  • Connection Handling: It handles connection drops and reconnections seamlessly. In a real-time chat application. Maintaining a stable connection is critical for user experience. 
  • Load Balancing: Centrifugo can distribute connections across multiple nodes. Providing load balancing and ensuring smoother performance under heavy loads. 

Security Considerations

  • Authentication and Authorization: Centrifugo supports JWT for secure client-server communication. Ensuring that messages are sent and received by authenticated users. 
  • Channel Privacy: It allows for private channels, where access can be controlled and managed. Thereby, adding an additional layer of security for sensitive communications. 

Performance and Reliability

  • Distributed System Support: Redis supports a distributed data structure, which aligns well with Centrifugo’s ability to run in a distributed manner. Thereby, it ensures that as the load increases, both Centrifugo and Redis can scale horizontally to manage the increased traffic effectively. 
  • High Performance: Redis is known for its high-performance capabilities, especially with in-memory data operations. Hence complementing Centrifugo’s real-time message processing, ensuring quick and efficient handling of real-time data. 

The Workflow of Integrating Centrifugo with Django

A Small Setup to Demonstrate work with Centrifugo

Django Set-up

Install Django 

pip install django 

 Create new Django project: 

django-admin startproject chat_project 

Navigate to your project directory and create a new Django app: 

python manage.py startapp chat 

Centrifugo Installation

  • Download the latest Centrifugo release from its official GitHub repository
  • Unzip and run the binary file to start the Centrifugo server. 
  • We can use Centrifugo with Docker too. 
    Create a simple configuration file (config.json): 
{
     “token_hmac_secret_key“: “your_token_hmac_secret_key”, 

    “admin_password“: “your_admin_pwd”, 

    “admin_secret”: “your_admin_secret“, 

    “api_key“: “your_api_key“, 

    “admin“: true, 

    “allowed_origins“: [“https://your_domain.extension“], 

    “allow_subscribe_for_client“: true, 

    “port“: “8000” 
}

Integrating Centrifugo with Django

Backend Configuration

In your Django settings, add necessary configurations for Centrifugo: 

CENTRIFUGO_HOST = 'http://localhost:8000' 

Client Side Set-up

Add Centrifugo’s JavaScript client to your HTML template: 

<script src="https://cdn.jsdelivr.net/npm/centrifuge@5.0.1/build/index.min.js"></script> 

Building the Chat Interface

Creating Chat Models

Define a Message model in models.py: 

from django.db import models 
class Message(models.Model): 
    text = models.TextField() 
    created_at = models.DateTimeField(auto_now_add=True) 

Django Views and URLs

Create a view to handle chat messages in views.py

from django.shortcuts import render 
from .models import Message 
 
def chat_room(request): 
    messages = Message.objects.all() 
    return render(request, 'chat/room.html', {'messages': messages}) 

Map the view to a URL in urls.py. 

Implementing Real Time Communication

Publishing Messages

When a message is sent, publish it to Centrifugo: 

import json 
import requests 
from django.conf import settings 
 
def publish_message(message): 
    data = { 
        'channel': 'chat', 
        'data': { 
            'text': message 
        } 
    } 
    headers = {X-API-Key: 'your_api key'} 
    url = f"{settings.CENTRIFUGO_HOST}/api/publish" 
    requests.post(url, data=json.dumps(data), headers=headers) 

Subscribing to a Channel

In your front-end, subscribe to the Centrifugo channel to receive messages: 

var centrifuge = new Centrifuge('ws://localhost:8000/connection/websocket'); 
centrifuge.subscribe("chat", function(message) { 
    console.log(message); 
}); 
centrifuge.connect(); 

Please note that the example provided is for demonstration purposes only. For a production-ready system, there are several important considerations to ensure optimal performance and security: 

  1. Choosing an Appropriate Database: Opt for databases that excel in high-write, low-read operations. Examples include Cassandra, ScyllaDB, or certain time-series databases. These are designed to handle large volumes of data efficiently, which is crucial for real-time applications. 
  1. Enforcing Authentication: Implement strict authentication protocols when clients connect to the socket server. This ensures that only authorized users can access the service. Enhancing the security of your system. 
  1. Using a Reverse Proxy: Place the socket server behind a reverse proxy, such as Nginx. This approach helps in mitigating Cross-Origin Resource Sharing (CORS) issues. A reverse proxy can also provide additional benefits like load balancing and SSL termination. These are essential for maintaining a secure and efficient production environment. 

Conclusion

Building a chat service with Django and Centrifugo provides a powerful combination for real-time web applications. By following the steps outlined in this guide, you can create a chat application that is scalable, efficient, and provides a seamless user experience. 

Looking for more tech insights? We’ve got you covered! 

Son Tran, Chief Technical Officer