Python Celery Logo

Django & Celery 4.0

En la ultima versión 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.

Tutorial con la versión actualizada de Celery la cual incluye cambios mayores. Celery & Django

Celery es un framework para el manejo de tareas basado en colas, basándose 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 librerías 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 agregamos 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 ahí 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 métodos con la anotación ‘@tasks’ de celery.

#Nota 4 Colocamos el broker que estaremos utilizados para guardar los jobs, en esta nueva versión 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 métodos de nuestro archivo ‘tasks.py‘ y ejecutarlos (Si, así de facil). Como solo tenemos una vista simple y de prueba ejecutamos la llamada ahí.

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 método 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, '[email protected]', [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", "[email protected]")

Y hasta aquí 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