Django & Celery 4.0

En la ultima version de Celery (4.0) llego con varios cambios que rompen previos desarrollos (Era de esperar) realizados con celery 3.1 (Lanzado en 2013), por ende decidí realizar un nuevo tutorial utilizando Django 1.10 y Celery 4.1, explicando a su vez los cambios que rompen previos desarrollos.

Este tutorial sera el mismo concepto que el anterior Celery & Django

Celery es un framework para el manejo de tareas basado en colas, basandoce en el patrón de diseño Productor consumidor donde el productor le envía trabajo a realizar al consumidor celery se encarga de manejarnos tanto el manejo de la cola de trabajos (jobs) como los workers (consumidores / trabajadores) que serán los que realicen dicha tarea. En este post estaremos integrando Django & Celery y algunos casos de usos para los que son buenos.

Podemos representar celery en el siguiente diagrama:

celery_django_integracion

Donde podemos ver que Celery en quien encola el job y es quien maneja los workers para procesar dichos jobs.

Entre las características principales de Celery se encuentran:

  • Poder ejecutar tareas de forma asíncronas.
  • Ejecutar tareas de forma recurrente algo así como crontabs.
  • Ejecutar tareas con una fecha en especifico.

Celery es uno de los frameworks mas importantes que he conocido en el entorno python, todo proyecto que quiera realizar una actividad en background lo primero que debe pensar es en Celery. Celery se integra bien con Django y es lo que veremos ahora.

h3>Instalación

Primero creamos nuestro proyecto Django

django-admin startproject app_mail

Luego creamos nuestro entorno dentro del proyecto Django y lo activamos

cd app_mail
virtualenv env
source env/bin/activate

Ahora instalamos los paquetes Celery y redis, desde la version 3.1 Django se integra perfectamente con Celery, por lo que no es necesario utilizar librerias como ‘Djcelery

pip install -U "Celery[redis]"

Ahora vamos a crear una aplicación simple para nuestro proyecto, la misma tendrá la funcionalidad de enviar un correo electrónico utilizando sendmail de Linux.

django-admin startapp celery_example

Luego tendremos que agregar nuestra aplicación ya creada a nuestras INSTALLED_APPS

Una vez instaladas vamos a generar y correr las migraciones.

python manage.py makemigrations
python manage.py migrate

Como estamos creando un proyecto simple la base de datos que este proyecto tendrá sera sqlite.

Creamos una vista simple que solo imprima un texto para fines de prueba y ejecución de Celery.

#celery_example/views.py
from django.shortcuts import render, HttpResponse

# Create your views here.
def index(request):
    return HttpResponse("Hola")

Y agregaremos esa vista a nuestro archivo de url.py

#app_mail/urls.py
from django.conf.urls import url
from django.contrib import admin

from celery_example.views import index

urlpatterns = [
    url(r'^$', index),
    url(r'^admin/', admin.site.urls),
]

Corremos nuestra aplicación

python manage.py runserver

Y tendremos nuestro “Hola” mostrado en pantalla.

Configurar Celery

Para configurar nuestro proyecto Django junto a Celery tenemos que crear un archivo llamado celery.py donde colocaremos la creación de nuestra aplicación celery y demás configuraciones.

from __future__ import absolute_import, unicode_literals
import os
from celery import Celery

# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'app_mail.settings')

app = Celery('proj') #Nota 1
app.config_from_object('django.conf:settings', namespace='CELERY') #Nota 2
app.autodiscover_tasks() #Nota 3

app.conf.update(
    BROKER_URL = 'redis://localhost:6379/0', #Nota 4
)

Bueno eso que vimos ahi arriba seria nuestra aplicación Celery, detallares los puntos importantes de el código colocado ahi arriba.

#Nota 1 Creamos nuestra aplicación celery y le pasamos un nombre

#Nota 2 Inicializamos nuestra app celery con la configuración de nuestro proyecto Django

#Nota 3 Como su nombre lo dice gracias a esta linea Celery auto-inspeccionara nuestras app y buscara metodos con la anotación ‘@tasks’ de celery.

#Nota 4 Colocamos el broker que estaremos utilizados para guardar los jobs, en esta nueva version de Celery no se puede utilizar Django y Beanstalk por falta de fondos para dicho soporte.

Ahora procederemos a en nuestra aplicación Django llamada ‘celery_example’ crearemos un archivo llamado ‘tasks.py’ donde colocaremos nuestras tareas a ejecutar.

#celery_example/tasks.py
from app_mail.celery import app

@app.task
def prueba_suma(x, y):
    return x + y
    
@app.task
def prueba_resta(x, y):
    return x - y

Una vez creadas nuestras majestuosas tareas, podemos proceder a correr nuestro proyecto Django y nuestra app celery (Son 2 procesos aparte).

En una terminal (Django app)

python manage.py runserver 8080

En otra terminal

celery worker -A app_mail.celery --loglevel=info

Es bueno correr la aplicación con el log level info así podremos ver las tareas que estas disponibles para ser ejecutadas en los workers de celery. Si todo se realizo bien en output de nuestra app celery seria algo como esto:

celerydjango_-_Cloud9

Para llamar una de estas tareas desde nuestro proyecto Django solo tenemos que importar los metodos de nuestro archivo ‘tasks.py‘ y ejecutarlos (Si, así de facil). Como solo tenemos una vista simple y de prueba ejecutaremos la llamada ahi.

from django.shortcuts import render, HttpResponse
from tasks import prueba_suma
    
# Create your views here.
def index(request):
    
    resultado = prueba_suma(5, 6)
    
    return HttpResponse("Hola")

Si ejecutamos nuestro metodo de esa forma se ejecutar en el foreground (Mientras el request este vivo) y no es lo que queremos para que se ejecute en los procesos de celery tendremos que hacerlo un poco diferente.

from django.shortcuts import render, HttpResponse
from tasks import prueba_suma
    
# Create your views here.
def index(request):
    
    resultado = prueba_suma.delay(5, 6)
    
    return HttpResponse("Hola")

De esta forma podremos ejecutarla en el background y podremos ver que en el output de celery tendremos algo como esto:

celerydjango_-_Cloud9

Donde nos muestra cuando la tarea entro a la cola de trabajo y cuando se ejecuto.

Ahora vamos a crear una tarea que nos permita enviar una correo, por que un correo bueno es un muy buen ejemplo de cosas que tenemos que hacer de forma asíncrona, nuestro usuarios no pueden estar esperando en el hilo principal de la aplicación a que enviemos un correo.

Tendremos que configurar los datos SMTP de nuestra aplicación Django

#settings.py
EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = ""
SERVER_EMAIL = ""
EMAIL_HOST_USER = ""
EMAIL_HOST_PASSWORD = ""

Y luego nuestra tarea para enviar correos:

#...
from django.core.mail import send_mail

@app.task
def enviar_mail(asunto, contenido, destinatario):
    send_mail(asunto, contenido, 'noreply@mail.com', [destinatario], fail_silently=False)

Para ejecutar dicha llamada solo tenemos que importarla y ejecutarla con delay para que se ejecute en los procesos de celery.

from tasks import enviar_mail

enviar_mail.delay("Asunto", "Contenido mensaje", "mail@mail.com")

Y hasta aqui este tutorial, espero que al igual que me sirvió a mi conocer esta herramienta le pueda servir a alguien mas y compartir el conocimiento.

Aqui coloco el código del ejemplo completo Github

Referencia

Celery
Django

Share on Google+Share on LinkedInShare on RedditShare on TumblrTweet about this on TwitterShare on Facebook