Consultar procesos con Celery dentro de uwsgi

Después de unos días de trabajo en mi entorno de desarrollo ha llegado el momento de poner la última versión de la aplicación que estoy haciendo a producción. Como el entorno de producción tiene una configuración distinta que la del entorno de desarrollo, aquí han empezado a aparecer los problemas.

Lo primero es que tenemos una cosa ahí enmedio que se llama uwsgi y es quien ejecuta el código, en lugar del python manage.py runserver. Una de las cosas que me he encontrado es que el trozo de código que comprueba que hay tareas ejecutándose en Celery, no funciona correctamente. En mi caso estaba usando

import time, json
_stats = os.popen('celery inspect stats --json').read()
time.sleep(1)
_stats = json.loads(_stats)

No funcionaba correctamente. He tenido que quebrarme un poco la cabeza para inspeccionar que es lo que estaba ocurriendo, por suerte existe una librería que se llama remote_pdb

(venv) root@app-dev:/var/www/html/app# pip3 install remote-pdb

Y añadimos lo siguiente en el trozo de código que queramos inspeccionar que esté corriendo a través de uwsgi

from remote_pdb import RemotePdb
RemotePdb('127.0.0.1', 4444).set_trace()

Y nos connectaremos al trace por telnet

root@digitplan-dev:~# telnet localhost 4444
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
/var/www/html/app/web/rrd.py(465)check_task_status()
-"""
(Pdb) 

A partir de aquí he podido comprobar que algo le pasa a celery, ya que cualquier comando que ejecutase con celery devolvía vacío. No me ha quedado otra que realizar esta comprobación de otra forma

from celery import Celery
_app = Celery("nombreapp")
_running_tasks = _app.control.inspect().active()['celery@' + str(hostname)]
_status 

Django: tareas en background con celery y rabbitmq

Venga, con este post vamos a subir un poco el nivel de nuestras aplicaciones!

Una de las problemáticas que te encuentras al programar con django es que el envío de mails es horrorosamente lento, el proceso de enviar el mail es relativamente rápido, pero no termino de entender el porqué en general es lento (la conexión y sobre todo la desconexión). Para ello una de las soluciones que más o menos ya había aplicado a mi manera con command hacía que la ejecución cada minuto se solapase con la ejecución de minutos anteriores. Hice una ñapa hace unos días hasta encontrar una solución un poco más elegante. Aquí os la traigo! :D

Hay varios posts que hablan de celery, incluso el libro que uso de consulta “Django 3 by Example”, hablan de usar @tank, pero esta opción está descontinuada para la versión 5, así que aquí veremos como hacerlo con Celery 5. Toda la info la he sacado de éste post.

Configurar e instalar celery y rabbitmq en nuestro proyecto/sistema
Lo primero será instalar celery en nuestro proyecto

laura@melatonina:~/dev/whistleblowerbox$ source venv/bin/activate
(venv) laura@melatonina:~/dev/whistleblowerbox$ pip install celery

A continuación instalamos rabbitmq en nuestro sistema. Rabbitmq es el servicio que encolará las tareas que le pasemos y luego las ejecutará en background

root@melatonina:~# apt -y install rabbitmq-server

Ahora en el fichero settings.py de nuestro proyecto añadimos

(venv) laura@melatonina:~/dev/whistleblowerbox$ vi wbox/settings.py
CELERY_BROKER_URL = 'amqp://localhost'

A continuación, en el mismo directorio donde se encuentra el fichero settings.py vamos a crear uno que se …