Django 1.10 + Celery + RabbitMQ

Hans Takeshi
Crehana
Published in
5 min readMay 15, 2018

Empezaré diciendo que es mi primer post en Medium, he estado avanzando un tanto en un blog personal (en serio, tengo que acabarlo), y espero que este primer relato me sirva como motivación. ≧◡≦

Si vienes trabajando con Djangito, te habrás dado cuenta que toma un tanto de tiempo en renderizar los datos hacia el template o almacenar algún dato en tu BBDD (dependiendo de las relaciones que tenga tu base de datos). En pocas palabras, el navegador hace una petición a nuestro servidor, Django hará todo lo necesario para responder al navegador, mientras este no responda, el navegador se quedará “pensando” y el usuario se arranca los pelos en aquella espera.

Acá aparece Celery, este se encargará de ejecutar una tarea en el background, sin tener la necesidad de esperar a que Django termine de responder :@ (también existen otras opciones como Huey y Pyres).

Para que Celery trabaje de forma adecuada, necesita de un broker. Un broker no es mas que un puente entre Django y Celery que les permitirá interactuar, para este ejemplo usaremos Rabbit (también podrían utilizar Redis).

Vamos a realizar un ejemplo sencillo de enviar un correo de bienvenida a la hora que un usuario se registre. ツ

Primero instalamos Celery dentro de nuestro entorno virtual:

pip install Celery

Una vez instalado vamos a crear un archivo llamado celery.py dentro de nuestra directorio de configuracion:

import os

from celery import Celery
from django.conf import settings

# set the default Django settings module for the celery program

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings.base')
app = Celery('celery prueba')

app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

Lo que hace este archivo es, primero setea una variable de entorno llamada DJANGO_SETTINGS_MODULE y como valor el archivo de configuracion de nuestra aplicación para que celery pueda utilizarlo, creamos una instancia de la clase Celery a la cual la hemos llamado app, utilizamos el metodo config_from_object para hacer referencia a nuestro archivo settings y con autodisconver_tasks descubrirá todas las tareas agregadas en cualquiera de nuestras apps de nuestro proyecto.

Para asegurarnos de que celery cargue al iniciar el proyecto, debemos agregar la siguiente linea en el archivo __init__.py de ese mismo directorio.

from celery import app as celery_app

Y ya! estamos listos para agregar celery en cualquier app de nuestro proyecto.

Para este ejemplo, vamos a agregar un archivo llamado tasks dentro de una de las aplicaciones (en mi caso en la app usuarios):

Dentro del archivo tasks.py, vamos a agregar una funcion sencilla donde lo que hará será el envio de correos en el momento que un usuario se registre a mi web de pruebillas:

from django.template.loader import get_template
from django.template import Context
from django.core.mail import EmailMessage
from django.conf import settings


def email_welcome_signup():
htmly = get_template('emails/email-create-user.html')
email_destino = 'email'
d = Context(email_destino)
html_content = htmly.render(d)
asunto = u'Crehana: Bienvenido a la familia'
mail = 'Crehana<{}>'.format(settings.DEFAULT_FROM_EMAIL)
msg = EmailMessage(asunto, html_content, mail, [email_destino, ])
msg.content_subtype = "html"
msg.send()

La funcion get_template, buscará el template con ruta “email/email-crete-user.html” dentro de la ruta que nosotros hayamos configurado en la variable TEMPLATES en nuestro archivo de configuración.

email_destino es el correo que se acaba de registrar, Context para renderizar la variable en un tipo diccionario, get_template cuenta con una funcion llamada “render”, que recibe un contexto. Al final creamos una instancia de la clase EmailMessage a la cual le pasamos 4 valores, asunto, html_content, mail y el (o los) destinos en una lista, seteamos el tipo de contenido con la funcion content_subtype y usamos la funcion send para concluir con el objetivo.

Hasta el momento no hemos utilizado Celery, para utilizarlo, solo necesitamos importar la funcion donde sea necesaria, en mi caso en la vista del register:

Ya casi!, ahora necesitamos instalar el broker, instalaremos RabbitMQ, pero este está escrito en Erlang ( ̄ヘ ̄), asi que necesitaremos instalar los siguientes paquetes:

sudo apt-get updatesudo apt-get upgradecd ~
wget http://packages.erlang-solutions.com/site/esl/esl-erlang/FLAVOUR_1_general/esl-erlang_20.1-1~ubuntu~xenial_amd64.deb
sudo dpkg -i esl-erlang_20.1-1\~ubuntu\~xenial_amd64.deb

(En ubuntu 16.04, quizá te diga que te falta instalar el paquete libsctp1)

sudo apt-get install libsctp1

Verificiamos que Erlang está instalado:

erl

Deberá mostrarte algo como:

Instalamos RabbitMQ, se pueden guiar del siguiente tutorial(https://www.vultr.com/docs/how-to-install-rabbitmq-on-ubuntu-16-04-47)

Una vez hecho todo esto, ya tendremos instalado rabbitMQ

Ya para terminar, solo necesitamos inicar celery en la consola, señalando el archivo celery.py que creamos al inicio:

celery -A settings worker -l info

Vamos a crearnos una cuenta en mi web de pruebillas ≧◡≦:

y boom, nos hemos logeado (∪ ◡ ∪)!

Veamos que sucedió!

La consola de Celery ejecutó la tarea asignada:

Y en Django, solo hizo el POST correspondiente del logging y nada más.

El email enviado:

Espero que este pequeño ejemplo les sirva de guía, pueden probar con Redis que es un tanto más sencillo a diferencia de RabbitMQ.

Greetings!

--

--