Real time messaging with Centrifugo

4 min read

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

Related posts

In this article, we will examine the best approaches for ReactJS state management and demonstrate how to maintain control over the state of your application. We shall see how ReactJS allows us to make a highly functionable app that benefits us to achieve our goals.
5 min read
In the software development world, coding isn't just about functionality. The code must also be maintainable and scalable. Writing Clean Code is an essential skill for every programmer. By writing Clean Code, you enhance your software not only for yourself but also for those who will maintain and develop it in the future. 
13 min read
In a space where the environment is filled with of relational databases, where data volumes are ever-expanding, the efficiency of SQL queries plays a pivotal role in maintaining optimal performance. One of the key elements in achieving this optimization is the strategic use of indexes. In this blog post, we will engage with advanced indexing strategies in SQL, exploring techniques that go beyond the basics
3 min read