Probleemoverzicht

Bij het verzenden van een webhook POST-verzoek van de DRF-server naar de Django-appserver,
kwamen er tijdens het aanmaken van Post modelinstantie-s problemen voor.

  1. Webhook timeout
  2. Na het aanmaken van het Post-object, kostte het tijd om de ManyToMany velden categories, tags te verwerken.
  3. Hierdoor werd de webhook-respons vertraagd en beschouwde DRF dit als een mislukking.

  4. Geen waarborging van gegevensconsistentie

  5. Wanneer de Celery-taak direct na de follow-up wordt aangeroepen, wordt deze aangeroepen op een moment dat tags.add(...), categories.add(...) nog niet voltooid zijn.
  6. Hierdoor ontstaan er problemen waarbij Celery onvolledige gegevens verwerkt.

  7. Ontvangst van lege gegevens in Celery, zelfs na on_commit()

  8. Na waarborging van de gegevensconsistentie met on_commit(), werd de Celery-taak gereserveerd, maar de resultaten van queries zoals tags.all() bleven nog steeds een lege lijst.
  9. Dit kwam omdat Celery leesbewerkingen naar de replica-DB stuurde en er een vertraging was in de synchronisatie van master naar replica.

Oplossingsstrategie

  1. Direct na het aanmaken van Post een antwoord retourneren
  2. Door alleen de Post-instantie aan te maken en onmiddellijk een 202 Accepted antwoord naar DRF te retourneren, kan het timeout-probleem worden omzeild.

  3. Volgwerkzaamheden in een aparte thread verwerken

  4. Gebruik van threading.Thread() om de relatieverwerking en Celery-aanroep van de hoofdflow te scheiden.
  5. Het ontwerp maakt het mogelijk dat de webhook-respons niet vertraagt.

  6. Garantie van transactie binnen post_process

  7. Verpak de hele verwerking van de ManyToMany velden in een transactie met transaction.atomic().
  8. Reserveer de Celery-taak na voltooiing van de taak met transaction.on_commit().
  9. Dit garandeert dat Celery wordt uitgevoerd nadat de relatieverwerking is voltooid.

  10. Specificeer de master DB voor queries binnen Celery

  11. Om consistentieproblemen door vertragingen in de replica te voorkomen, gebruik expliciet using('default') binnen de Celery-taak.
post = Post.objects.using('default').get(id=post_id)
tags = post.tags.using('default').all()
categories = post.categories.using('default').all()

Of gebruik een DB-router om ervoor te zorgen dat Celery-verzoeken altijd de master-DB raadplegen.


Samenvatting van de eindstructuur

  1. DRF-server → Django webhook-verzoek
  2. Django:
    • Antwoord onmiddellijk teruggeven na het aanmaken van een Post-object.
    • Volgwerkzaamheden worden in een aparte thread uitgevoerd.
  3. Binnen de thread:
    • Relaties beheren met atomic().
    • Reserveer de Celery-taak met on_commit().
  4. Celery:
    • Data ophalen uit de master DB (default).

Conclusie

Elke component functioneert individueel goed, maar om de latency en gegevensconsistentieproblemen die optreden in een gedistribueerde architectuurovergang op te lossen,
was er niet alleen een goede code-architectuur nodig, maar ook systeemontwerp dat rekening houdt met gegevensstromen, timing en vertragingen van de database-replicas.