Question

Alors, j'ai une application qui utilise Twisted + Stomper en tant que client STOMP qui cultive des travaux à un multiprocessing.Pool des travailleurs.

Cela semble bien fonctionner quand je viens d'utiliser un script python pour tirer tout ça, qui (simplifié) ressemble à quelque chose comme ceci:

# stompclient.py

logging.config.fileConfig(config_path)
logger = logging.getLogger(__name__)

# Add observer to make Twisted log via python
twisted.python.log.PythonLoggingObserver().start() 

# initialize the process pool.  (child processes get forked off immediately)
pool = multiprocessing.Pool(processes=processes)

StompClientFactory.username = username
StompClientFactory.password = password
StompClientFactory.destination = destination
reactor.connectTCP(host, port, StompClientFactory())
reactor.run()

Comme cela se packagés pour le déploiement, je pensais que je profiterais du script twistd et exécuter ce fichier à partir d'un tac.

Voici mon fichier tac très similaire prospectifs:

# stompclient.tac

logging.config.fileConfig(config_path)
logger = logging.getLogger(__name__)

# Add observer to make Twisted log via python
twisted.python.log.PythonLoggingObserver().start() 

# initialize the process pool.  (child processes get forked off immediately)
pool = multiprocessing.Pool(processes=processes)

StompClientFactory.username = username
StompClientFactory.password = password
StompClientFactory.destination = destination

application = service.Application('myapp')

service = internet.TCPClient(host, port, StompClientFactory())
service.setServiceParent(application)

Par souci d'illustration, je se sont effondrés ou changé quelques détails; espérons qu'ils ne sont pas l'essence du problème. Par exemple, mon application a un système de plug-in, la piscine est initialisé par une méthode distincte, et le travail est déléguée à la piscine en utilisant des méthodes pool.apply_async () en passant l'un des processus de mon plug-in ().

Donc, si je lance le script (stompclient.py), tout fonctionne comme prévu.

Il semble également fonctionner OK si je lance torsion en mode non-démon (-n):

twistd -noy stompclient.tac

cependant, il ne pas travail quand je lance en mode démon:

twistd -oy stompclient.tac

L'application semble démarrer OK, mais quand il tente de bifurquer le travail, il se bloque juste. Par « se bloque », je veux dire qu'il semble que le processus d'enfant n'a jamais demandé de faire quoi que ce soit et le parent (qui a appelé pool.apply_async ()) juste assis là, attendant la réponse à revenir.

Je suis sûr que je fais quelque chose de stupide avec multitraitement Twisted +, mais je pense vraiment que quelqu'un peut expliquer à mon la faille dans mon approche.

Merci d'avance!

Était-ce utile?

La solution

Puisque la différence entre votre appel de travail et votre appel non travail est que l'option « -n », il semble plus probable que le problème est causé par le processus de démonisation (qui « -n » empêche de se produire).

Sur Posix, l'une des étapes de démonisation est bifurquent et ayant la sortie de parent. Parmi des choses, cela a pour conséquence de faire tourner votre code dans un processus différent de celui dans lequel le fichier a été évalué .tac. Cela a également reformate la relation enfant / parent des processus qui ont été démarrés dans le fichier de .tac -. Que votre piscine de processus multitraitement étaient

Les processus de piscine multitraitement commencent avec un parent du processus de twistd commencer. Toutefois, lorsque ce processus sort dans le cadre de démonisation, leur parent devient le processus d'initialisation du système. Cela peut causer des problèmes, bien que probablement pas le problème de suspension que vous avez décrit. Il y a probablement d'autres détails de mise en œuvre de la même faible niveau qui permettent normalement le module de multitraitement pour travailler, mais qui sont perturbés par le processus de démonisation.

Heureusement, en évitant cette étrange interaction devrait être simple. Les API de service de Twisted vous permettent d'exécuter du code après démonisation est terminée. Si vous utilisez ces API, vous pouvez retarder l'initialisation du pool de processus de module de multitraitement qu'après démonisation et nous espérons éviter le problème. Voici un exemple de ce qui pourrait ressembler à:

from twisted.application.service import Service

class MultiprocessingService(Service):
    def startService(self):
        self.pool = multiprocessing.Pool(processes=processes)

MultiprocessingService().setServiceParent(application)

Maintenant, séparément, vous pouvez également rencontrer des problèmes liés à nettoyer des processus enfants du module multiprocessing, ou peut-être des problèmes avec les processus créés avec l'API de création de processus de Twisted, reactor.spawnProcess. En effet, une partie de traiter les processus enfants correctement implique généralement la manipulation du signal SIGCHLD. Twisted et multitraitement ne vont pas à coopérer à cet égard, bien que, si l'un d'entre eux va être averti de tous les enfants qui sortent et l'autre ne seront jamais avisés. Si vous n'utilisez l'API Twisted pour créer des processus enfants du tout, alors cela peut être acceptable pour vous - mais vous pouvez vérifier pour vous assurer que tout gestionnaire de signal du module multiprocessing tente d'installer en fait « victoires » et ne reçoit pas remplacé par le propre gestionnaire de Twisted.

Autres conseils

Une idée possible pour vous ...

Lors de l'exécution en mode démon twistd fermera stdin, stdout et stderr. Est-ce quelque chose que vos clients ne lisent ou écrivent ces?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top