Django y Celery en 2026: Procesamiento Asíncrono y Preguntas de Entrevista
Guía completa de Django y Celery en 2026: configuración, colas, tareas periódicas, monitoreo con Flower, comparativa con Django 6.0 y preguntas de entrevista técnica.

Django y Celery conforman la dupla más sólida para el procesamiento asíncrono de tareas en el ecosistema Python. En cualquier aplicación web moderna construida con Django, existen operaciones que no pueden ni deben ejecutarse dentro del ciclo de solicitud-respuesta HTTP. El envío de correos electrónicos, la generación de reportes PDF, el procesamiento de imágenes y la sincronización con APIs externas son ejemplos clásicos de tareas que bloquean el hilo principal del servidor y degradan la experiencia del usuario. Con la llegada de Celery 5.6 y Django 6.0 en 2026, el panorama evoluciona, pero Celery permanece como la solución más robusta para escenarios de producción a gran escala.
Celery desacopla las operaciones costosas en tiempo del ciclo solicitud-respuesta. Una vista Django envía una tarea hacia un broker de mensajes (Redis o RabbitMQ), y un proceso worker separado la ejecuta de manera asíncrona. Este patrón gestiona el envío de emails, la generación de reportes, el procesamiento de imágenes y cualquier carga de trabajo que de otra forma bloquearía al usuario.
Integración de Celery con Django: configuración inicial
La integración de Celery con Django requiere un archivo de configuración dedicado en el paquete principal del proyecto. Este archivo inicializa la aplicación Celery, vincula la configuración de Django y habilita el autodescubrimiento de tareas en todas las aplicaciones instaladas.
# myproject/celery.py
import os
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
app = Celery('myproject')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()El parámetro namespace='CELERY' indica que todas las configuraciones de Celery en settings.py deben tener el prefijo CELERY_. Esto evita colisiones de nombres con otras configuraciones de Django. El método autodiscover_tasks() recorre cada aplicación registrada en INSTALLED_APPS buscando un módulo tasks.py, lo que permite una organización limpia y modular.
La configuración del broker y el backend de resultados se define en el archivo de settings del proyecto. Redis es la opción más utilizada en producción por su velocidad y simplicidad:
# myproject/settings.py
CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'UTC'Es importante utilizar bases de datos Redis separadas (índices 0 y 1) para el broker y el backend de resultados. Esto facilita la depuración y permite aplicar políticas de persistencia diferenciadas para cada función.
Escritura y despacho de tareas asíncronas
El decorador @shared_task es la forma recomendada de definir tareas en aplicaciones Django reutilizables, ya que no depende de una instancia específica de la aplicación Celery. El siguiente ejemplo muestra una tarea de envío de correo electrónico con manejo robusto de errores y reintentos automáticos:
# orders/tasks.py
from celery import shared_task
from django.core.mail import send_mail
from orders.models import Order
@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def send_order_confirmation(self, order_id: int) -> str:
"""Send confirmation email for a completed order."""
try:
order = Order.objects.select_related('user').get(id=order_id)
send_mail(
subject=f'Order #{order.id} Confirmed',
message=f'Your order totaling {order.total} has been confirmed.',
from_email='noreply@example.com',
recipient_list=[order.user.email],
)
return f'Email sent for order {order_id}'
except Order.DoesNotExist:
return f'Order {order_id} not found'
except Exception as exc:
# Retry on transient failures (SMTP timeout, etc.)
raise self.retry(exc=exc)Existen varios patrones clave en este ejemplo. El parámetro bind=True inyecta la instancia de la tarea como primer argumento (self), lo cual es necesario para invocar self.retry(). Se utiliza select_related('user') para evitar una consulta adicional al acceder al correo del usuario. Los errores transitorios como timeouts de SMTP activan el mecanismo de reintento, mientras que un Order.DoesNotExist se maneja de forma diferente porque reintentar no resolverá el problema.
El despacho de la tarea desde una vista de Django se realiza con el método .delay(), que envía la tarea a la cola de forma no bloqueante:
# orders/views.py
from orders.tasks import send_order_confirmation
def complete_order(request, order_id):
# ... process payment, update order status ...
send_order_confirmation.delay(order_id)
return redirect('order_success', order_id=order_id)Un principio fundamental es pasar siempre identificadores simples (como order_id) en lugar de objetos completos. Los objetos Django no son serializables de forma segura, y además los datos podrían cambiar entre el momento del despacho y la ejecución de la tarea.
Enrutamiento de tareas y gestión de colas
En aplicaciones de producción con cargas de trabajo heterogéneas, es esencial separar las tareas en colas diferenciadas. Esto permite asignar recursos específicos a cada tipo de trabajo y evitar que tareas pesadas bloqueen a las rápidas:
# myproject/settings.py
CELERY_TASK_ROUTES = {
'orders.tasks.send_order_confirmation': {'queue': 'notifications'},
'reports.tasks.generate_monthly_report': {'queue': 'reports'},
'images.tasks.resize_upload': {'queue': 'media'},
}Cada cola se consume mediante un worker dedicado con configuración de concurrencia adaptada al tipo de carga:
# Start notification worker (fast tasks, high concurrency)
celery -A myproject worker -Q notifications -c 8 --loglevel=info
# Start report worker (slow tasks, limited concurrency)
celery -A myproject worker -Q reports -c 2 --loglevel=info
# Start media worker (CPU-bound, prefork pool)
celery -A myproject worker -Q media -c 4 -P prefork --loglevel=infoLa cola de notificaciones utiliza alta concurrencia (-c 8) porque el envío de correos es una operación intensiva en E/S que pasa la mayor parte del tiempo esperando respuestas de red. La cola de reportes limita la concurrencia a 2 para evitar sobrecargar la base de datos con consultas masivas. La cola de medios usa el pool prefork para tareas que consumen CPU como el redimensionamiento de imágenes.
¿Listo para aprobar tus entrevistas de Django?
Practica con nuestros simuladores interactivos, flashcards y tests técnicos.
Tareas periódicas con Celery Beat
Celery Beat funciona como un planificador de tareas tipo cron, integrado directamente con el ecosistema de Celery. Permite programar tareas recurrentes sin depender del crontab del sistema operativo:
# myproject/settings.py
from celery.schedules import crontab
CELERY_BEAT_SCHEDULE = {
'cleanup-expired-sessions': {
'task': 'accounts.tasks.cleanup_expired_sessions',
'schedule': crontab(hour=3, minute=0), # Daily at 3 AM UTC
},
'sync-inventory': {
'task': 'inventory.tasks.sync_external_inventory',
'schedule': 300.0, # Every 5 minutes
},
'generate-weekly-digest': {
'task': 'notifications.tasks.send_weekly_digest',
'schedule': crontab(hour=9, minute=0, day_of_week='monday'),
},
}El servicio Beat se ejecuta como un proceso independiente:
celery -A myproject beat --loglevel=infoEs crítico ejecutar una única instancia de Celery Beat en todo el clúster. Múltiples instancias generarían tareas duplicadas. En entornos con múltiples servidores, herramientas como django-celery-beat permiten almacenar la programación en la base de datos y coordinarse mediante bloqueos.
Monitoreo con Flower
Flower es la herramienta estándar de monitoreo para Celery. Proporciona un dashboard web en tiempo real que muestra el estado de los workers, las tareas activas, las colas pendientes y las estadísticas históricas:
# Install and run Flower
pip install flower
celery -A myproject flower --port=5555Flower expone métricas que son fundamentales para la operación en producción: tiempos de ejecución promedio por tarea, tasa de fallos, profundidad de colas y uso de memoria por worker. Estas métricas pueden integrarse con sistemas de alertas como Prometheus o Datadog para detectar cuellos de botella antes de que afecten a los usuarios.
Celery 5.6 también introdujo mejoras en la journalización estructurada que se integra con agregadores de logs JSON, ofreciendo una eficiencia de depuración superior según las notas de lanzamiento.
Django 6.0: sistema de tareas nativo versus Celery
Django 6.0, lanzado en 2026, introduce un sistema nativo de tareas en segundo plano. Este sistema permite encolar tareas simples sin dependencias externas, utilizando backends como base de datos o Redis directamente desde Django.
Sin embargo, es fundamental entender las diferencias de alcance. El sistema integrado de Django 6.0 está diseñado para casos de uso sencillos: enviar un correo, actualizar un caché o ejecutar una operación rápida en segundo plano. Celery, por su parte, ofrece un ecosistema completo:
- Procesamiento distribuido en múltiples máquinas
- Colas prioritarias y enrutamiento de tareas
- Limitación de velocidad y políticas de reintento avanzadas
- Planificación periódica (Celery Beat)
- Seguimiento de resultados con backends configurables
- Workflows canvas (chains, groups, chords) para orquestación de tareas complejas
La recomendación para 2026 es directa: si el proyecto requiere únicamente tareas simples y de baja complejidad, el sistema nativo de Django 6.0 reduce la carga operativa. Para cualquier aplicación con requerimientos de procesamiento asíncrono no triviales, Celery sigue siendo la opción superior.
Preguntas frecuentes en entrevistas técnicas
Las entrevistas técnicas para posiciones backend con Python evalúan con frecuencia el conocimiento de Celery. Las siguientes preguntas representan los temas más evaluados en entrevistas Django en 2026.
P: ¿Por qué se deben pasar IDs en lugar de objetos a las tareas?
Los objetos Django contienen estado de conexión a la base de datos y no son serializables de forma segura con JSON. Además, el estado del objeto puede cambiar entre el momento del despacho y la ejecución. Pasar el ID garantiza que la tarea trabaje con los datos más recientes al consultar la base de datos.
P: ¿En qué se diferencia self.retry() de despachar manualmente la tarea?
self.retry() preserva el contador de intentos, aplica el límite max_retries configurado y utiliza backoff exponencial por defecto. Llamar manualmente a .delay() crea una tarea nueva con el contador reiniciado, lo que puede generar bucles de reintento infinitos ante fallos persistentes.
P: ¿Qué sucede cuando un worker falla durante la ejecución de una tarea?
Con CELERY_TASK_ACKS_LATE = True, la tarea no se reconoce hasta que finaliza exitosamente. Si el worker muere, el broker reenvía la tarea a otro worker disponible. Con CELERY_TASK_REJECT_ON_WORKER_LOST = True, la tarea se rechaza explícitamente y se reencola.
P: ¿Cuál es la diferencia entre .delay(), .apply_async() y llamar la tarea directamente?
.delay(*args) es azúcar sintáctico para .apply_async(args=args). .apply_async() acepta opciones adicionales como countdown, eta, queue, priority y expires. Llamar la función de tarea directamente (sin .delay()) la ejecuta de manera síncrona en el proceso actual — útil para testing pero contrario al propósito del procesamiento asíncrono.
P: ¿Cómo interactúa una capa de caché con los resultados de tareas Celery?
Los resultados de tareas almacenados en el backend Celery pueden cachearse mediante el framework de caché de Django. Una vista verifica primero el caché; si no existe, despacha la tarea y almacena el identificador AsyncResult. Las solicitudes subsiguientes consultan el backend de resultados mediante el identificador en caché hasta que la tarea finalice, luego cachean el resultado final.
P: ¿Cuándo conviene usar el sistema nativo de Django 6.0 en lugar de Celery?
El sistema nativo es apropiado para tareas simples que no requieren enrutamiento, reintentos sofisticados ni workflows complejos. Celery es necesario cuando se requiere control granular sobre colas, concurrencia, tareas periódicas y monitoreo en tiempo real.
Lista de verificación para despliegue en producción
La configuración de producción requiere ajustes específicos que garanticen la fiabilidad y el rendimiento del sistema:
# myproject/settings.py — Production configuration
CELERY_TASK_ALWAYS_EAGER = False # Never True in production
CELERY_TASK_ACKS_LATE = True # Redelivery on worker crash
CELERY_WORKER_PREFETCH_MULTIPLIER = 1 # Fair scheduling
CELERY_TASK_REJECT_ON_WORKER_LOST = True # Reject on unexpected exit
CELERY_TASK_TIME_LIMIT = 300 # Hard kill after 5 minutes
CELERY_TASK_SOFT_TIME_LIMIT = 240 # SoftTimeLimitExceeded after 4 min
CELERY_WORKER_MAX_TASKS_PER_CHILD = 1000 # Prevent memory leaks
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = TrueLos workers deben ejecutarse como servicios gestionados por systemd para garantizar reinicio automático ante fallos:
# /etc/systemd/system/celery-worker.service
[Unit]
Description=Celery Worker
After=network.target redis.service
[Service]
Type=forking
User=django
Group=django
WorkingDirectory=/opt/myproject
ExecStart=/opt/myproject/venv/bin/celery -A myproject worker \
--loglevel=info --concurrency=4 --pidfile=/var/run/celery/worker.pid
ExecStop=/bin/kill -s TERM $MAINPID
Restart=always
[Install]
WantedBy=multi-user.targetElementos esenciales para la verificación previa al despliegue incluyen configurar CELERY_TASK_ALWAYS_EAGER = False, establecer límites de tiempo para evitar workers bloqueados, habilitar TASK_ACKS_LATE junto con TASK_REJECT_ON_WORKER_LOST para garantizar que ninguna tarea se pierda, limitar MAX_TASKS_PER_CHILD para prevenir fugas de memoria, y monitorear las colas con Flower o Prometheus.
¡Empieza a practicar!
Pon a prueba tu conocimiento con nuestros simuladores de entrevista y tests técnicos.
Conclusión
- Celery 5.6.3 (marzo 2026) aporta correctivos de fugas de memoria, journalización estructurada, soporte de colas de quórum y compatibilidad con psycopg3 — la actualización desde versiones anteriores es altamente recomendable.
- Siempre pasar claves primarias a las tareas, nunca objetos ORM. Esto previene errores de serialización y datos obsoletos.
- Enrutar las tareas hacia colas dedicadas según las características de carga. Las notificaciones rápidas y los reportes lentos nunca deben competir por los mismos workers.
- Usar
acks_late=Truecombinado con diseño idempotente de tareas para cargas críticas que deben sobrevivir a fallos de workers. - Definir
time_limitysoft_time_limiten cada tarea para evitar que workers bloqueados consuman recursos indefinidamente. - Django 6.0 maneja tareas simples en segundo plano de forma nativa; Celery sigue siendo necesario para procesamiento distribuido, planificación y workflows canvas.
- Monitorear la profundidad de las colas y las tasas de reintento con Flower o agregación de logs estructurados para detectar problemas de capacidad antes de que afecten a los usuarios.
Etiquetas
Compartir
Artículos relacionados

Django 5.2: Middleware Personalizado y Manejo de Señales para Entrevistas Técnicas
Guía completa sobre middleware personalizado y señales en Django 5.2. Implementación de middleware de logging, middleware asíncrono, señales pre_save/post_save y preguntas frecuentes de entrevista.

Preguntas de Entrevista Django y Python: Top 25 en 2026
Las 25 preguntas mas frecuentes en entrevistas de Django y Python. ORM, vistas, middlewares, DRF, signals y optimizacion con respuestas detalladas y ejemplos de codigo.

Django ORM: optimizar las consultas para un rendimiento máximo
Guía completa para optimizar las consultas del ORM de Django. select_related, prefetch_related, índices, análisis del problema N+1 y técnicas avanzadas para aplicaciones de alto rendimiento.