Pregunta

Por lo tanto, tengo una aplicación que utiliza Twisted + Stomper como cliente STOMP, que cultiva un trabajo a un multiprocessing.Pool de los trabajadores.

Esto parece funcionar bien cuando sólo tiene que utilizar un script en Python para disparar con esto, que (simplificado) se ve algo como esto:

# 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()

A medida que esto se envasa para su despliegue, pensé que iba a tomar ventaja de la secuencia de comandos y ejecutar twistd esto desde un archivo tac.

Aquí está mi archivo tac muy similares de aspecto:

# 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)

En aras de la ilustración, que han colapsado o cambiado algunos detalles; es de esperar que no eran la esencia del problema. Por ejemplo, mi aplicación tiene un sistema de plugins, la piscina se inicializa mediante un método independiente, y entonces el trabajo se delega a la piscina utilizando pool.apply_async () que pasa a una de proceso de mi plugin de () métodos.

Por lo tanto, si se me acaba el guión (stompclient.py), todo funciona como se esperaba.

También parece funcionar bien si me quedo giro en el modo de no-daemon (-n):

twistd -noy stompclient.tac

Sin embargo, lo hace no de trabajo cuando corro en modo demonio:

twistd -oy stompclient.tac

La aplicación parece que se inician correctamente, pero cuando se trata de la horquilla fuera del trabajo, simplemente se cuelga. Por "cuelga", me refiero a que parece que el proceso de niño nunca se le pide que hacer nada y el padre (que se llama pool.apply_async ()) sólo se sienta allí esperando la respuesta para volver.

Estoy seguro de que estoy haciendo algo estúpido con Twisted + multiprocesamiento, pero estoy realmente esperando que alguien puede explicar a mi la falla en mi enfoque.

Gracias de antemano!

¿Fue útil?

Solución

Dado que la diferencia entre su invocación de trabajo y su invocación de no trabajo es sólo la opción "-n", parece más probable que el problema es causado por el proceso de daemonization (que "-n" evita que suceda).

En POSIX, uno de los pasos involucrados en daemonization es que se bifurcan y con la salida de los padres. Entre las cosas, esto tiene la consecuencia de que su código se ejecute en un proceso diferente de aquel en el que se evaluó el archivo .tac. Esto también se re-organiza la relación hijo / padre de los procesos que se iniciaron en el archivo .tac -. Como su grupo de procesos de multiprocesamiento eran

Los procesos de la piscina multiprocesamiento comienzan con uno de los padres del proceso twistd de empezar. Sin embargo, cuando ese proceso sale como parte de daemonization, su padre se convierte en el proceso de inicio del sistema. Esto puede causar algunos problemas, aunque probablemente no es el problema que cuelga usted describió. Probablemente hay otros detalles de implementación de manera similar a nivel bajo, lo que normalmente permiten que el módulo de multiprocesamiento para trabajar, pero que se ven perturbadas por el proceso daemonization.

Afortunadamente, evitando esta extraña interacción debe ser sencillo. API del servicio de Twisted le permiten ejecutar código después de daemonization ha completado. Si utiliza estas API, a continuación, puede retrasar la inicialización del proceso de la piscina del módulo de multiprocesamiento hasta después daemonization y es de esperar evitar el problema. Aquí está un ejemplo de lo que podría ser:

from twisted.application.service import Service

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

MultiprocessingService().setServiceParent(application)

Ahora, por separado, también puede tener problemas relacionados con la limpieza de procesos hijo del módulo de multiprocesamiento, o, posiblemente, problemas con los procesos creados con la API de creación de procesos de trenzado, reactor.spawnProcess. Esto es debido a que parte de tratar con procesos secundarios implica correctamente general, el manejo de la señal SIGCHLD. Retorcido y multiprocesamiento no van a estar cooperando en este sentido, sin embargo, por lo que uno de ellos va a ser notificado de todos los niños que salen y el otro nunca serán notificados. Si no se utiliza la API de trenzado para crear procesos secundarios en absoluto, entonces esto puede estar bien para usted - pero es posible que desee comprobar para asegurarse de que cualquier manejador de la señal del módulo de multiprocesamiento intenta instalar en realidad "gana" y no recibe reemplazado por el propio manejador de trenzado.

Otros consejos

Una posible idea para usted ...

Cuando se ejecuta en modo demonio twistd cerrará stdin, stdout y stderr. Hace algo que sus clientes no leen o escriben a estos?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top