Comment j'ai construit un système de synchronisation « Set It and Forget It »
Les prix des produits changent à de nombreux endroits. Ils changent dans le panneau d'administration, via des imports groupés ou par des webhooks d'API.
Si vous voulez synchroniser ces changements avec une place de marché externe, vous faites face à un problème. Ajouter un appel de synchronisation à chaque chemin de code est une erreur. Vous en oublierez un. Vous en casserez un. La maintenance devient un cauchemar.
Les signaux Django résolvent ce problème. Vous vous connectez à l'événement de sauvegarde du modèle (model save event). Cela permet de capturer chaque changement en un seul endroit.
Mais les signaux ont un défaut. Si vous mettez à jour 100 prix d'un coup, le signal se déclenche 100 fois. Cela déclenche 100 appels d'API. Vous allez atteindre les limites de débit (rate limits) ou gaspiller des ressources.
J'utilise un modèle en trois parties pour corriger cela :
• Un gestionnaire de signaux (signal handler) qui collecte les IDs au lieu d'agir immédiatement.
• Un ensemble (set) par thread pour supprimer les doublons.
• Un callback de vidage (flush callback) utilisant transaction.on_commit pour tout traiter d'un coup.
Voici comment cela fonctionne.
Utilisez
threading.local()N'utilisez pas de variable globale. Les variables globales partagent l'état entre les requêtes. Cela peut entraîner des fuites de données.threading.local()permet de garder les données isolées dans un seul thread.Enregistrez, n'agissez pas Le gestionnaire de signaux ajoute simplement l'ID du produit à un ensemble (set). Il demande ensuite à Django d'exécuter une fonction de vidage (flush function) uniquement après la réussite de la transaction de la base de données. Cela évite de synchroniser des données qui n'ont pas pu être sauvegardées.
Traitez par lots (batch) Lorsque la transaction est validée (commit), la fonction de vidage s'exécute. Elle copie l'ensemble et le vide. Ensuite, elle envoie la liste complète des IDs à une couche de service (service layer).
La couche de service effectue une seule requête groupée (bulk query) pour récupérer tous les produits. Elle les regroupe par magasin. Enfin, elle envoie une seule tâche à Celery par magasin.
Les avantages sont clairs :
- La déduplication est automatique. Un ensemble (set) s'en occupe pour vous.
- La sécurité des transactions est intégrée. Vous ne synchronisez jamais de données annulées (rolled-back).
- L'efficacité est élevée. Vous évitez les problèmes de requêtes N+1.
- La fiabilité est élevée. Celery gère les tentatives de réessai si l'API échoue.
Vous construisez le système une seule fois. Chaque nouvelle fonctionnalité que vous ajouterez plus tard fonctionnera automatiquement avec le système de synchronisation.
Comment gérez-vous les synchronisations d'API externes dans Django ? Utilisez-vous des signaux ou un autre modèle ?
Source : https://dev.to/acel/how-i-built-a-set-it-and-forget-it-sync-system-with-django-signals-2ld7