Coding, iPython, Linux

Procesos asincrónicos en Django con Celery, RabbitMQ y Flower

@brberis
March 27, 2016

Para administrar tareas en background de un proyecto Django debemos realizarlo con uno o varios servicios daemon residentes en el servidor los cuales procesen las tareas de manera asincrónica sin interrumpir la dinámica de la interfaz front-end 

En la siguiente configuración se realizara un ejemplo simple de envíos de email gatillados por un formulario o registro de usuario. Lo primero que vamos a hacer es instalar RabbitMQ en nuestro servidor.

sudo apt-get install rabbitmq-server

Luego comprobamos que este correctamente instalado con,

rabbitmq-server

Vamos a ver un output Starting broker...

Luego instalamos Celery en nuestro enviroment,

pip install celery

Vamos a instalar django-celery-email para facilitar el proceso.

pip install django-celery-email

Creamos un modulo junto a settings.py llamado celery.py con el siguiente código,

	
	import os
from celery import Celery
from django.conf import settings

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proyecto.settings')
app = Celery('proyecto')


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



Dentro de nuestra aplicación también debemos modificar __init__.py para que nuestro modulo celery.py sea cargando una vez django corra.

	
	from .celery import app as celery_app

Agregamos en settings.py la nueva aplicación en INSTALLED_APPS 'djcelery_email' y configuramos nuestros datos de configuración smtp. En este caso gmail. 

	
	EMAIL_BACKEND = 'djcelery_email.backends.CeleryEmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_PASSWORD = 'password autorizada para esta app' #Esta password se obtiene del proceso de verificación 2 de gmail'
EMAIL_HOST_USER = 'usuario_de_gmail'
EMAIL_PORT = 587
EMAIL_USE_TLS = True

Es importante utilizar el backend de django-celery-email djcelery_email.backends.CeleryEmailBackend.

Ahora no olvidemos migrar con .manage.py migrate antes de continuar.

Por consenso debemos crear nuestras tareas en tasks.py en el directorio de nuestra aplicación que enviara los procesos.

	
	from celery import task 
from django.core.mail import send_mail 


@task 
def mail_nuevo_form(nombre_form): 
	""" En este ejemplo se envía un email cuando un formulario es enviado""" 
	subject = 'Formulario {}'. format(nombre_form)
	message = 'Nuevo formulario enviado con éxito!' 
	mail_sent = send_mail( subject, message, 'correo@servidor.com', ['correo@destinatario.com']) 
	return mail_sent

En el ejemplo anterior la tarea se realiza simplemente agregando un decorador python @task de Celery.

Luego importamos nuestra tarea desde views.py  y la agregamos a nuestro método:

# tarea asincrónica 
mail_nuevo_form.delay(nombre_form)

 

En producción debemos tener nuestros servicios Celery y RabbitMQ cargados. Para esto podemos utilizar Supervisor.

Agregamos los scripts in nuestro long_script.conf de supervisor.

sudo vi /etc/supervisor/conf.d/long_script.conf

[program:rabbitmq]
command=/etc/supervisor/rabbitmq.sh
autostart=true
autorestart=true
stderr_logfile=/var/log/rabbitmq.err.log
stdout_logfile=/var/log/rabbitmq.out.log

[program:celery]
command=/home/env/mi_env/celery.sh
autostart=true
autorestart=true
stderr_logfile=/var/log/celery.err.log
stdout_logfile=/var/log/celery.out.log

[program:flower]
command=/home/env/mi_env/flower.sh
autostart=true
autorestart=true
stderr_logfile=/var/log/flower.err.log
stdout_logfile=/var/log/flower.out.log

 

Donde /etc/supervisor/rabbitmq.sh tenemos,

#!/bin/bash
trap "{ echo Deteniendo rabbitmq; rabbitmqctl stop; exit 0; }" EXIT

exec /usr/sbin/rabbitmq-server

 

Donde /home/env/mi_env/celery.sh,

#!/bin/bash
source /home/env/mi_env/bin/activate
cd /home/django/proyecto
export C_FORCE_ROOT="true"
celery -A proyecto worker -l info 


Y donde /home/env/mi_env/flower.sh tenemos,

#!/bin/bash
source /home/env/mi_env/bin/activate
cd /home/django/proyecto
celery -A proyecto flower

 

Para que supervisor pueda ejecutar los archivos debemos dar el permiso correspondiente,

sudo chmod +x /etc/supervisor/rabbitmq.sh
sudo chmod +x /home/env/mi_env/celery.sh
sudo chmod +x /home/env/mi_env/flower.sh

 

Agregamos la nueva configuracion a supervisor,

sudo supervisorctl reread
sudo supervisorctl update
sudo service supervisor restart

Ahora damos acceso a root a ejecutar Celery,

export C_FORCE_ROOT="true"

En el último script de supervidor esta Flower que es un monitor web de tareas de Celery. Si no la tenemos instalada lo hacemos con,

pip install flower

Podemos utilizar el navegador con el puerto 5555 para entrar a Flower .

 

 

 

blog comments powered by Disqus