2009-03-18 11 views
51

Escribí una pequeña aplicación de Python que se ejecuta como daemon. Utiliza subprocesos y colas.Comunicación con un demonio python en ejecución

Estoy buscando enfoques generales para modificar esta aplicación para que pueda comunicarme con ella mientras se está ejecutando. Sobre todo me gustaría ser capaz de controlar su salud.

En pocas palabras, me gustaría ser capaz de hacer algo como esto:

python application.py start # launches the daemon 

Más tarde, me gustaría ser capaz de venir y hacer algo como:

python application.py check_queue_size # return info from the daemonized process 

Para ser claro, no tengo ningún problema para implementar la sintaxis inspirada en Django. Lo que no tengo idea de cómo hacer es enviar señales al proceso daemonizado (inicio), o cómo escribir el daemon para manejar y responder a tales señales.

Como dije antes, estoy buscando enfoques generales. El único que puedo ver en este momento es decirle al daemon que registre constantemente todo lo que pueda necesitarse para un archivo, pero espero que haya una manera menos complicada de hacerlo.

ACTUALIZACIÓN: Wow, un montón de buenas respuestas. Muchas gracias. Creo que veré los enfoques de Pyro y web.py/Werkzeug, ya que Twisted es un poco más de lo que quiero morder en este momento. El próximo desafío conceptual, supongo, es cómo hablar con mis hilos de trabajo sin colgarlos.

Gracias de nuevo.

Respuesta

19

¿Qué tal si se ejecuta un servidor http?

Parece una locura, pero la ejecución de un simple servidor web para administrar su servidor requiere sólo unas pocas líneas utilizando web.py

También puede considerar la creación de una tubería UNIX.

+0

También +1 para la interfaz HTTP. Una secuencia de comandos python puede analizar las opciones de línea de comandos y enviar comandos XMLRPC a un servidor HTTP interno. –

+0

+1: HTTP. Incruste una pequeña aplicación WSGI en el daemon para responder a las solicitudes. –

+1

(y @VanGale y @ S.Lott) ¿podría alguien proporcionar una referencia/ejemplo para ejecutar un servidor http con el propósito de recibir comandos como el OP descrito? Necesito hacer esto, pero me gustaría un poco más de detalle. – synaptik

5

Suponiendo que está bajo * nix, puede enviar señales a un programa en ejecución con kill desde un shell (y análogos en muchos otros entornos). Para manejarlos desde Python, consulte el módulo signal.

+0

¿Se puede enviar cualquier señal a través de 'kill'? Si no, tal vez modifiques esta respuesta como 'kill', según mi leal saber y entender, solo puede enviar una señal de 'muerte', que no es particularmente útil aquí – puk

+0

@puk en realidad envías otras señales con kill usando tu '-s 'parámetro, por ejemplo 'kill -s QUIT '. –

9

Lo usaría trenzado con una tubería con nombre o simplemente abriría un zócalo. Eche un vistazo al servidor de eco y al cliente examples. Debería modificar el servidor de eco para verificar si hay alguna cadena pasada por el cliente y luego responder con la información solicitada.

Debido a los problemas de subprocesamiento de Python, tendrá problemas para responder a las solicitudes de información y al mismo tiempo continuará haciendo lo que el demonio debe hacer de todos modos. Las técnicas asincrónicas o la bifurcación de otros procesos son su única opción real.

+1

+1 para Twisted, vea también twisted.manhole que proporciona una interfaz de telnet directamente en el intérprete en ejecución: http://twistedmatrix.com/projects/core/documentation/howto/telnet.html –

+0

"[...] usted es va a tener problemas para responder a las solicitudes de información mientras simultáneamente continúa haciendo lo que el daemon debe hacer de todos modos " Creo que esta afirmación no es compatible. Si te refieres al GIL, no evita este tipo de concurencia. –

+0

Um, ¿qué "problemas de enhebrado" serían esos? –

7
# your server 

from twisted.web import xmlrpc, server 
from twisted.internet import reactor 

class MyServer(xmlrpc.XMLRPC): 

    def xmlrpc_monitor(self, params):   
     return server_related_info 

if __name__ == '__main__': 
    r = MyServer() 
    reactor.listenTCP(8080, Server.Site(r)) 
    reactor.run() 

cliente puede ser editada en el xmlrpclib, comprobar el código de ejemplo here.

+0

Puede escribir fácilmente el servidor y el cliente sin depender de retorcidos, pero esta es una buena respuesta. –

16

Use werkzeug y haga que su daemon incluya un servidor WSGI basado en HTTP.

Su daemon tiene una colección de pequeñas aplicaciones WSGI para responder con información de estado.

Su cliente simplemente usa urllib2 para realizar solicitudes POST o GET a localhost: somePort. Su cliente y servidor deben aceptar el número de puerto (y las URL).

Esto es muy simple de implementar y muy escalable. Agregar nuevos comandos es un ejercicio trivial.

Tenga en cuenta que su daemon no tiene que responder en HTML (aunque a menudo es sencillo). Nuestros daemons responden a las solicitudes WSGI con objetos de estado codificados en JSON.

34

Otro enfoque más: use Pyro (objetos remotos de Python).

Pyro básicamente le permite publicar instancias de objetos de Python como servicios que se pueden llamar de forma remota. He usado Pyro para el propósito exacto que describes, y encontré que funciona muy bien.

De forma predeterminada, un daemon de servidor Pyro acepta conexiones desde cualquier lugar. Para limitar esto, utilice un validador de conexión (consulte la documentación) o suministre host='127.0.0.1' al constructor Daemon para escuchar únicamente las conexiones locales.

código Ejemplo tomado de la documentación Pyro:

servidor

 
import Pyro.core 

class JokeGen(Pyro.core.ObjBase): 
     def __init__(self): 
       Pyro.core.ObjBase.__init__(self) 
     def joke(self, name): 
       return "Sorry "+name+", I don't know any jokes." 

Pyro.core.initServer() 
daemon=Pyro.core.Daemon() 
uri=daemon.connect(JokeGen(),"jokegen") 

print "The daemon runs on port:",daemon.port 
print "The object's uri is:",uri 

daemon.requestLoop() 

Client

 
import Pyro.core 

# you have to change the URI below to match your own host/port. 
jokes = Pyro.core.getProxyForURI("PYROLOC://localhost:7766/jokegen") 

print jokes.joke("Irmen") 

Otro proyecto similar es RPyC. No he probado RPyC.

4

Podría asociarlo con Pyro (http://pythonhosted.org/Pyro4/) el objeto remoto de Python. Le permite acceder de forma remota a objetos Python. Es fácil de implementar, tiene una sobrecarga baja y no es tan invasivo como Twisted.

+0

Creo que el enlace que proporcionaste para Pyro es otro pyro (un software de análisis termodinámico), no el que crees que es (o al menos es AHORA). – ironstein

+0

Las cosas cambian en siete años. He actualizado con el repositorio actual. – directedition

Cuestiones relacionadas