Resumen del Problema

Se envió una solicitud POST de webhook desde el servidor DRF al servidor de aplicaciones Django,
y Django encontró el siguiente problema durante el proceso de creación de una instancia del modelo Post.

  1. Tiempo de espera de respuesta del webhook superado
  2. Después de la creación del objeto Post, se requiere tiempo para procesar los campos ManyToMany como categories y tags
  3. Esto provoca un retraso en la respuesta del webhook y DRF lo interpreta como un fracaso

  4. No se asegura la integridad de los datos

  5. Si se llama a la tarea de Celery de inmediato para el procesamiento posterior, se llama en un momento en que las operaciones tags.add(...), categories.add(...) aún no se han completado
  6. Esto resulta en que Celery procese datos incompletos

  7. Recepción de datos vacíos en Celery incluso después de on_commit()

  8. Se reservó la tarea de Celery después de asegurar la integridad de los datos con on_commit(), pero los resultados de las consultas como tags.all() todavía mostraron listas vacías
  9. Esto se debe a que Celery estaba enviando las operaciones de lectura a la base de datos réplica, y existía un retraso en la sincronización de master a réplica

Estrategia de Solución

  1. Devolver la respuesta inmediatamente después de crear el Post
  2. Creando solo la instancia de Post y devolviendo inmediatamente una respuesta de 202 Accepted a DRF para evitar problemas de tiempo de espera

  3. Procesar trabajos posteriores en un hilo separado

  4. Utilizando threading.Thread() para separar el procesamiento de relaciones y la llamada a Celery del flujo principal
  5. Diseñado para no hacer que la respuesta del webhook se retrase

  6. Asegurar la transacción dentro de post_process

  7. Envolver todo el procesamiento del campo ManyToMany con transaction.atomic()
  8. Reservar la tarea de Celery con transaction.on_commit() después de completar las operaciones
  9. Esto asegura que Celery se ejecute después de completar el procesamiento de relaciones

  10. Especificar directamente la base de datos master para las consultas dentro de Celery

  11. Para evitar problemas de integridad debido a los retrasos en la réplica, utilizar using('default') explícitamente dentro de la tarea de Celery
post = Post.objects.using('default').get(id=post_id)
tags = post.tags.using('default').all()
categories = post.categories.using('default').all()

También se puede utilizar un DB Router para dirigir las solicitudes de Celery a que siempre consulten la base de datos master


Resumen de la Estructura Final

  1. Servidor DRF → Solicitud de webhook de Django
  2. Django:
    • Devolver respuesta inmediatamente después de crear el objeto Post
    • Los trabajos posteriores se ejecutan en un hilo separado
  3. Dentro del hilo:
    • Limpiar relaciones con atomic()
    • Reservar tarea de Celery con on_commit()
  4. Celery:
    • Consultar datos desde la base de datos master (default)

Conclusión

Aunque todos los componentes operan normalmente de manera individual,
es necesario un diseño del sistema que considere no solo la estructura del código, sino también el flujo de datos y los tiempos, así como los retrasos de las bases de datos réplicas, para solucionar problemas de latencia e integridad de datos en un entorno arquitectónico distribuido.