5 votes

Comment dois-je stocker l'état d'un processus longuement exécuté invoqué depuis Django ?

Je travaille sur une application Django qui permet à un utilisateur de télécharger des fichiers. J'ai besoin d'effectuer un traitement côté serveur sur ces fichiers avant de les envoyer à Amazon S3 . Après avoir lu les réponses à cette question y cet article de blog J'ai décidé que la meilleure façon de gérer ce problème était de demander à mon gestionnaire de vue d'invoquer une méthode sur Pyro pour effectuer le traitement de manière asynchrone et renvoyer immédiatement un Http 200 au client. J'ai prototypé cela et cela semble bien fonctionner, cependant, j'aimerais également stocker l'état du traitement afin que le client puisse interroger l'application pour voir si le fichier a été traité et téléchargé sur S3.

Je peux gérer l'interrogation assez facilement, mais je ne suis pas sûr de l'endroit approprié pour stocker l'état du processus. Il doit pouvoir être écrit par le processus Pyro et lu par ma vue d'interrogation.

  • J'hésite à ajouter des colonnes à la base de données pour des données qui ne devraient persister que pendant 30 à 60 secondes.
  • J'ai envisagé d'utiliser la fonction API de cache de bas niveau et l'utilisation d'un identifiant de fichier comme clé, mais je ne crois pas que ce soit vraiment ce pour quoi le cadre de cache est conçu et je ne suis pas sûr des problèmes imprévus qui pourraient survenir en suivant cette voie.
  • Enfin, j'ai envisagé de stocker l'état dans l'objet Pyro qui effectue le traitement, mais il semble que je doive ajouter une colonne de base de données booléenne "processing_complete" pour que la vue sache si elle doit ou non interroger l'état de l'objet Pyro.

Bien entendu, le découplage de l'état de la base de données pose également des problèmes d'intégrité des données (que se passe-t-il si le serveur tombe en panne et que toutes les données sont en mémoire ?) J'aimerais savoir comment des développeurs d'applications web plus expérimentés gèreraient ce type de traitement avec état.

6voto

S.Lott Points 207588

Pour ce faire, nous disposons d'un tableau "Demande" dans la base de données.

Lorsque le téléchargement arrive, nous créons l'objet Fichier téléchargé et nous créons une demande.

Nous lançons le traitement par lots en arrière-plan.

Nous renvoyons une page 200 "nous y travaillons" - elle montre les demandes et leur statut.

Notre processeur de traitement par lots utilise l'ORM de Django. Lorsqu'il termine, il met à jour l'objet Request. Nous pouvons (mais ne le faisons pas) envoyer une notification par courriel. La plupart du temps, nous nous contentons de mettre à jour le statut afin que l'utilisateur puisse se reconnecter et voir que le traitement est terminé.


Notes sur l'architecture du serveur Batch.

Il s'agit d'un serveur WSGI qui attend sur un port une demande de traitement par lots. La demande est un POST REST avec un numéro d'identification ; le processeur de traitement par lots le recherche dans la base de données et le traite.

Le serveur est démarré automatiquement par notre interface REST. S'il n'est pas en cours d'exécution, nous le lançons. Cela donne l'impression que les transactions des utilisateurs sont lentes, mais tant pis. Il n'est pas censé se bloquer.

De plus, nous avons une simple crontab pour vérifier qu'il est en cours d'exécution. Au maximum, il sera indisponible pendant 30 minutes entre les vérifications "are you alive ? Nous n'avons pas de script de démarrage formel (nous fonctionnons sous Apache avec mod_wsgi), mais nous pouvons créer un script de "redémarrage" qui touche le fichier WSGI et effectue ensuite un POST vers une URL qui effectue un contrôle de santé (et démarre le processeur batch).

Lorsque le serveur batch démarre, il peut y avoir des demandes non traitées pour lesquelles il n'a jamais reçu de POST. Ainsi, le démarrage par défaut est de retirer TOUT le travail de la file d'attente des requêtes -- en supposant qu'il ait pu manquer quelque chose.

5voto

Je sais qu'il s'agit d'une vieille question, mais quelqu'un pourrait trouver ma réponse utile même après tout ce temps, alors voici.

Vous pouvez bien sûr utiliser une base de données comme file d'attente, mais il existe des solutions développées exactement dans ce but.

AMQP est conçu à cet effet. Avec Céleri ou Carotte et un serveur de courtage comme LapinMQ ou ZeroMQ .

C'est ce que nous utilisons dans notre dernier projet et cela fonctionne très bien.

Pour votre problème, Celery et RabbitMQ semblent être la meilleure solution. RabbitMQ assure la persistance de vos messages, et Celery expose des vues faciles pour l'interrogation afin de vérifier l'état des processus exécutés en parallèle.

Vous pouvez également être intéressé par octopie .

1voto

brianz Points 3528

C'est donc d'une file d'attente que vous avez besoin. Dans votre cas, je choisirais absolument la DB pour sauvegarder l'état, même si ces états sont de courte durée. Cela semble répondre à toutes vos exigences et n'est pas terriblement difficile à mettre en œuvre puisque vous avez déjà toutes les pièces mobiles à votre disposition. Restez simple, sauf si vous besoin quelque chose de plus complexe.

Si vous avez besoin de quelque chose de plus puissant ou de plus sophistiqué, j'envisagerais quelque chose comme Gearman .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X