Saltar al contenido

Lección 15 de 21 · Lectura y práctica

Práctica: Crear un Sistema de Envío de Emails Asíncrono

Tipo de lección: VideoConcepto claveEn sistemas backend modernos, el procesamiento asíncrono es esencial para manejar tareas que no requieren respuesta inmediata al usuario, como el envío de emails. Imagina un restaurante: cuando.

Del concepto a la práctica

Taller de esta lección

El objetivo es desacoplar la respuesta de registro del trabajo de correo. El laboratorio usa destinatarios ficticios y un worker simulado que registra “preparado”; no entrega mensajes reales. El trabajo debe incluir una clave idempotente para que un reintento no duplique el efecto lógico.

Ejemplo resuelto

text
{"id":"mail-22","to":"ana@example.test","plantilla":"bienvenida","usuario":22}

El productor responde 202 aceptado tras encolar. El worker consulta mail-22; si ya está marcado como enviado-simulado, no repite la operación.

El ejemplo secuencial reconoce duplicados simulados, pero enviar correo y luego marcar enviado deja una ventana de duplicación si el worker muere. En producción verifica garantías del proveedor/idempotency key y diseña outbox y reconciliación; no marques enviado antes del efecto para ocultar ese problema. Aquí usa solo un registro local enviado-simulado y ninguna integración de correo; la autorización de la práctica no incluye enviar a personas.

Pruébalo

  1. Encola un correo de bienvenida ficticio.

  2. Consume y registra el estado enviado-simulado.

  3. Ejecuta de nuevo el mismo ID.

  4. Cuenta efectos y errores.

Comprueba tu resultado

Error frecuente: considerar que devolver 202 confirma entrega. Corrige diciendo que solo confirma aceptación del trabajo. Resultado esperado: una respuesta de aceptación, un único efecto simulado para mail-22, ningún envío externo y un segundo intento clasificado como duplicado o ya procesado.

Diagrama de decisión con ramas Sí y No y un bucle que procesa cada elemento de una lista.
CursaloMapa de práctica
Cómo avanza un programa

Una condición decide qué camino ejecuta el programa. Un bucle repite una operación mientras queden elementos, y termina cuando la lista se agota. Separar ambas ideas ayuda a seguir el flujo y comprobar casos límite.

Ver la infografía en tamaño completo ↗

Tipo de lección: Video

Concepto clave

En sistemas backend modernos, el procesamiento asíncrono es esencial para manejar tareas que no requieren respuesta inmediata al usuario, como el envío de emails. Imagina un restaurante: cuando pides comida, el mesero toma tu orden (síncrono) pero la cocina la prepara en segundo plano (asíncrono). Redis, con su estructura de datos listas y el patrón productor-consumidor, permite crear colas de trabajos eficientes donde:

  • Productores: Agregan tareas a la cola (ej. "enviar email de bienvenida")
  • Consumidores: Procesan tareas en segundo plano
  • Redis: Actúa como broker confiable que almacena las tareas pendientes

Este enfoque desacopla el tiempo de respuesta del usuario del tiempo de procesamiento real, mejorando la escalabilidad y experiencia del usuario.

Cómo funciona en la práctica

Implementaremos una cola usando Redis Lists con comandos LPUSH (agregar trabajo) y BRPOP (consumir bloqueante). Paso a paso:

  1. Configuración inicial:
    import redis
    r = redis.Redis(host='localhost', port=6379, db=0)
    QUEUE_NAME = 'email_queue'
  2. Productor (cuando un usuario se registra):
    email_data = {
        'to': 'usuario@ejemplo.com',
        'subject': 'Bienvenida',
        'body': 'Gracias por registrarte'
    }
    r.lpush(QUEUE_NAME, json.dumps(email_data))
  3. Consumidor (worker en segundo plano):
    while True:
        # BRPOP espera hasta 30 segundos por un trabajo
        result = r.brpop(QUEUE_NAME, timeout=30)
        if result:
            queue_name, email_json = result
            email_data = json.loads(email_json)
            # Lógica real de envío de email
            send_email(email_data)

La magia está en BRPOP: bloquea hasta que haya trabajo disponible, evitando polling constante.

Caso de estudio

E-commerce "TechShop" con 10,000 pedidos diarios. Problema: Los emails de confirmación demoraban 5 segundos por pedido, causando timeout en picos. Solución con Redis:

MétricaAntesDespués
Tiempo respuesta API5-8 segundos200 ms
Emails fallados15% en picos0.1%
Costo servidores8 instancias3 instancias

Implementación: Un solo productor (API de pedidos) y 5 workers consumiendo de la cola. Cada worker procesa hasta 100 emails/minuto.

Clave: Los workers son stateless y escalables horizontalmente según carga.

Errores comunes

  • No manejar fallos en workers: Si un worker crashea procesando un trabajo, este se pierde. Solución: Usar RPOPLPUSH a una lista de "procesando" y verificar timeout.
  • Colas infinitas sin monitoreo: Si los workers son más lentos que los productores, la cola crece hasta llenar memoria Redis. Implementar alertas cuando longitud > 10,000.
  • Serialización incorrecta: Enviar objetos complejos sin serializar causa errores. Usar JSON o MessagePack consistentemente.
  • Single point of failure: Redis single node sin replicación. En producción, usar Redis Cluster o al menos replica con persistencia.
  • Falta de idempotencia: Si un email se envía dos veces por retry, debe ser inocuo. Los emails deben tener ID único y verificación de duplicados.

Checklist de dominio

  1. Puedo explicar la diferencia entre procesamiento síncrono y asíncrono con una analogía del mundo real
  2. He implementado una cola productor-consumidor usando Redis Lists
  3. Sé cómo manejar fallos de workers sin perder trabajos
  4. Puedo monitorear el tamaño y throughput de una cola Redis
  5. Entiendo cuándo usar BRPOP vs RPOP en diferentes escenarios
  6. He configurado múltiples workers que consumen de la misma cola
  7. Puedo justificar por qué una cola Redis es mejor que una base de datos para este caso

Implementa un sistema de notificaciones con reintentos inteligentes

Extiende el sistema básico de emails para manejar fallos y reintentos. Sigue estos pasos:

  1. Crea un script Python que simule un productor que agrega 100 notificaciones a una cola 'notifications'
  2. Implementa un worker que consuma con BRPOP, pero que falle aleatoriamente el 20% de las veces (simula error de red)
  3. Cuando falle, mueve el trabajo a una cola 'retry' con timestamp usando RPOPLPUSH
  4. Crea un segundo worker que procese la cola 'retry' después de 60 segundos (usar timestamp)
  5. Agrega métricas: trabajos exitosos, fallados, en reintento
  6. Ejecuta 1 productor y 3 workers simultáneamente

Entrega: Código completo y captura de pantalla mostrando las métricas después de procesar todas las notificaciones.

Pistas
  • Usa time.time() para agregar timestamp a los trabajos fallados
  • Para el worker de reintentos, verifica si han pasado más de 60 segundos antes de procesar
  • Considera usar Redis Hashes para almacenar métricas de forma estructurada

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.

Sigue con Redis en Producción: Cache, Sesiones y Colas para Backend Engineers

Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.

Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.

01 / ELEGIR UNA RUTA

El próximo paso

Aprende IA mientras construyes algo que sí necesitas.

Empieza por el curso inicial o explora el catálogo para encontrar una práctica alineada con tu trabajo.