Aperçu du problème
Un serveur DRF a envoyé une requête POST webhook au serveur d'application Django et,
Django a rencontré les problèmes suivants lors de la création d'une instance du modèle Post.
- Délai d'attente de la réponse du webhook
- Après la création de l'objet Post, le traitement des champs
ManyToMany
commecategories
ettags
prend du temps -
En conséquence, la réponse du webhook est retardée et DRF l'identifie comme un échec
-
Intégrité des données non garantie
- Si une tâche Celery est appelée immédiatement après le traitement, les opérations
tags.add(...)
etcategories.add(...)
n'ont pas encore été complétées -
Ce qui entraîne un problème où Celery traite des données incomplètes
-
Réception de données vides par Celery même après on_commit()
- Bien que l'intégrité des données ait été garantie avec
on_commit()
et que la tâche Celery ait été planifiée, les résultats des requêtes commetags.all()
apparaissent toujours comme une liste vide - Cela est dû au fait que Celery envoyait des opérations de lecture à la base de données en réplique, et qu'il y avait un retard dans la synchronisation des données de la base de données principale vers la réplique
Stratégie de résolution
- Retourner la réponse immédiatement après la création du Post
-
Créer uniquement l'instance Post et retourner immédiatement une réponse
202 Accepted
à DRF afin d'éviter le problème de délai d'attente -
Traiter les travaux suivants dans un fil séparé
- Utiliser
threading.Thread()
pour séparer le traitement des relations et l'appel de Celery du flux principal -
Concevoir pour que la réponse du webhook ne ralentisse pas
-
Assurer la transaction à l'intérieur de post_process
- Regrouper l'ensemble du traitement des champs
ManyToMany
dans une transaction avectransaction.atomic()
- Planifier la tâche Celery après l'achèvement des travaux avec
transaction.on_commit()
-
Ce qui garantit que Celery s'exécute après le traitement des relations
-
Désigner directement la base de données principale dans Celery pour les requêtes
- Pour éviter les problèmes d'intégrité dus au retard de la réplique, utiliser explicitement
using('default')
dans la tâche Celery
post = Post.objects.using('default').get(id=post_id)
tags = post.tags.using('default').all()
categories = post.categories.using('default').all()
Ou il est possible d'utiliser un routeur de base de données pour s'assurer que les requêtes Celery interrogent toujours la base de données principale
Résumé de la structure finale
- Serveur DRF → Requête webhook Django
- Django:
- Réponse retournée immédiatement après création de l'objet Post
- Travaux suivants exécutés dans un fil séparé
- À l'intérieur du thread:
- Organisation des relations avec
atomic()
- Planification de la tâche Celery avec
on_commit()
- Organisation des relations avec
- Celery:
- Interroger les données de la base de données principale (
default
)
- Interroger les données de la base de données principale (
Conclusion
Tous les composants fonctionnent individuellement, mais pour résoudre les problèmes de latence et d'intégrité des données survenant dans un environnement d'architecture distribuée,
une conception système prenant en compte non seulement la structure du code mais aussi le flux de données, le timing et le retard de la base de données en réplique s'est avérée nécessaire.
Add a New Comment