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:
- 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.
- Concurrency: Handling multiple concurrent connections in real-time is challenging with Django alone, as its architecture is not optimized for this kind of workload.
- 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:
- 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.
- 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.
- 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