Je suis relativement novice en matière de Python, car je viens d'une formation en .Net.
La version courte : Comment puis-je créer un singleton à l'échelle de l'application ou un autre mécanisme permettant à plusieurs threads/processus de communiquer entre eux ?
Je suis peut-être gâté, mais en .Net, je créerais simplement quelque chose en App_Start
ou quelque chose d'autre au niveau de l'application. Comment puis-je faire la même chose en python/uwsgi ?
La version longue :
Nous disposons d'une API reposante écrite à l'aide de Django.
Certains appels nécessitent un prétraitement avant d'être transmis à un système dorsal qui effectue des opérations de longue durée.
Le flux actuel ressemble à quelque chose comme...
- Recevoir une demande de traitement de tous les documents correspondant à des critères donnés
- L'API détermine les documents qui correspondent à ces critères (de l'ordre de 100 000 - cela prend 15 à 20 secondes).
- L'Api génère un uuid pour cette demande de lot
- L'API publie un message dans une file d'attente pour chacun de ces documents, en se référant à l'identifiant du lot.
- L'Api écoute une autre file d'attente pour les messages "complétés" et compte les succès/échecs pour chaque identifiant de lot (~1-15 minutes).
- Pendant le traitement, l'utilisateur peut demander une mise à jour pour un numéro de lot spécifique.
Nous devons écouter la file d'attente des réponses en utilisant un thread différent de celui qui est utilisé pour servir les pages, puisqu'il se trouve dans un thread de type attendre la boucle d'attente ...
while True:
self.channel.wait()
Je gérais cela en obtenant une référence à un fichier QueueManager
qui est un singleton. Le gestionnaire lance la demande initiale, enregistre l'identifiant du lot, puis, dans un second thread, surveille la file d'attente et met à jour l'état local.
Nous ne nous soucions pas vraiment de préserver l'état à long terme - si les messages sont dans la file d'attente, le traitement sera effectué par le back-end et la surveillance de l'état n'est qu'un indice pour l'utilisateur que les choses sont en cours. S'il s'éloigne, il perd également l'accès à l'état (l'identifiant du lot est stocké en mémoire dans le JS).
Cela présente plusieurs avantages : nous avons évité d'utiliser une base de données pour synchroniser les informations (et le nettoyage associé). Nous avons pu utiliser un seul thread comme consommateur de messages et n'avons pas eu à nous préoccuper des problèmes de concurrence, car un seul thread collectera les messages et mettra à jour l'état local.
Donc... Maintenant qu'il est temps de l'exécuter en utilisant uwsgi, j'ai trouvé un problème majeur. Si je mets le nombre de processus à 1, le singleton fonctionne comme prévu, mais toutes les requêtes sont bloquées pendant les 15 à 20 secondes où l'api traite les données. C'est clairement inacceptable. A l'inverse, si je lance plusieurs workers, chacun a son propre singleton et son propre message listener - il est donc assez aléatoire de savoir si l'éditeur et le consommateur sont le même processus. Et même si c'est le cas, la demande de mise à jour de statut n'aboutira probablement pas à ce même processus.
Comment puis-je échanger des informations sur les états entre plusieurs travailleurs ? Existe-t-il un moyen d'utiliser plusieurs threads au lieu de plusieurs workers ?
Il semble que j'en aie vraiment besoin :
- n threads, chacun servant des requêtes
- 1 thread à l'écoute de la file d'attente
- un moyen de communication en mémoire entre eux
Note J'ai déjà --enable-threads
mais cela ne semble s'appliquer qu'aux nouveaux fils de discussion que je crée (je ne sais pas pourquoi cela ne serait pas activé par défaut).