2009-03-18 7 views
51

J'ai écrit une petite application Python qui fonctionne en tant que démon. Il utilise le filetage et les files d'attente.Communiquer avec un démon python en cours d'exécution

Je cherche des approches générales pour modifier cette application afin que je puisse communiquer avec elle pendant son fonctionnement. La plupart du temps, j'aimerais pouvoir surveiller sa santé.

En un mot, je voudrais pouvoir faire quelque chose comme ceci:

python application.py start # launches the daemon 

Plus tard, je voudrais être en mesure de venir et de faire quelque chose comme:

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

Pour être clair, je n'ai aucun problème à implémenter la syntaxe inspirée de Django. Ce que je n'ai aucune idée de comment faire est d'envoyer des signaux au processus démonisé (start), ou comment écrire le démon pour gérer et répondre à de tels signaux.

Comme je l'ai dit plus haut, je suis à la recherche d'approches générales. Le seul que je puisse voir en ce moment est de dire au démon de consigner en permanence tout ce qui pourrait être nécessaire dans un fichier, mais j'espère qu'il y a une façon moins compliquée de le faire.

MISE À JOUR: Wow, beaucoup de bonnes réponses. Merci beaucoup. Je pense que je vais regarder à la fois Pyro et les approches web.py/Werkzeug, puisque Twisted est un peu plus que ce que je veux mordre à ce stade. Le prochain défi conceptuel, je suppose, est de savoir comment parler à mes fils de travail sans les raccrocher.

Merci encore.

Répondre

19

Qu'en est-il de l'exécution d'un serveur http?

Il semble fou, mais l'exécution d'un simple serveur web pour votre serveur administration ne nécessite que quelques lignes à l'aide web.py

Vous pouvez également envisager de créer un tuyau unix.

+0

Egalement pour l'interface HTTP. Un script python peut analyser les options de ligne de commande et envoyer des commandes XMLRPC à un serveur HTTP interne. –

+0

+1: HTTP. Intégrez une petite application WSGI dans le démon pour répondre aux demandes. –

+1

(et @VanGale et @ S.Lott) quelqu'un pourrait-il fournir une référence/exemple pour l'exécution d'un serveur http dans le but de recevoir des commandes comme l'OP décrit? Je dois le faire, mais j'aimerais un peu plus de détails. – synaptik

5

En supposant que vous êtes sous * nix, vous pouvez envoyer des signaux à un programme en cours d'exécution avec kill à partir d'un shell (et des analogues dans de nombreux autres environnements). Pour les gérer depuis python, consultez le module signal.

+0

Pouvez-vous envoyer un signal via 'kill'? Si ce n'est pas le cas, peut-être reformuler cette réponse comme «tuer», au meilleur de ma connaissance, ne peut envoyer qu'un signal «tuer», ce qui n'est pas particulièrement utile ici – puk

+0

@puk vous envoyez réellement d'autres signaux avec kill en utilisant vous -s 'paramètre, par exemple 'kill -s QUIT '. –

9

Je voudrais utiliser tordu avec un tuyau nommé ou simplement ouvrir une douille. Jetez un oeil au serveur echo et au client examples. Vous devrez modifier le serveur echo pour vérifier la présence d'une chaîne passée par le client, puis répondre avec les informations demandées. En raison des problèmes de threading de Python, vous allez avoir du mal à répondre aux demandes d'informations tout en continuant à faire ce que le démon est censé faire de toute façon. Les techniques asynchrones ou le forking d'autres processus sont votre seule vraie option.

+1

+1 pour Twisted, voir aussi twisted.manhole qui fournit une interface telnet directement dans l'interpréteur en cours d'exécution: http://twistedmatrix.com/projects/core/documentation/howto/telnet.html –

+0

"[...] vous êtes J'aurais du mal à répondre aux demandes d'information tout en continuant à faire ce que le démon est censé faire de toute façon " Je trouve cette demande non supportée. Si vous parlez du GIL, cela n'empêche pas du tout ce genre de concurence. –

+0

Um, quels "problèmes de thread" seraient ceux-ci? –

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

client peut être écrit en utilisant xmlrpclib, consultez un exemple de code here.

+0

Vous pouvez facilement écrire le serveur et le client sans dépendre de torsadé, mais c'est une bonne réponse. –

16

Utilisez werkzeug et faites en sorte que votre démon inclue un serveur WSGI basé sur HTTP.

Votre démon a une collection de petites applications WSGI pour répondre avec des informations d'état.

Votre client utilise simplement urllib2 pour envoyer des requêtes POST ou GET à localhost: somePort. Votre client et votre serveur doivent être d'accord sur le numéro de port (et l'URL).

Ceci est très simple à mettre en œuvre et très évolutif. L'ajout de nouvelles commandes est un exercice trivial. Notez que votre démon n'a pas à répondre en HTML (c'est souvent simple, cependant). Nos démons répondent aux requêtes WSGI avec des objets d'état codés en JSON.

34

Encore une autre approche: utilisez Pyro (objets distants Python).

Pyro vous permet essentiellement de publier des instances d'objets Python en tant que services pouvant être appelés à distance. J'ai utilisé Pyro dans le but précis que vous décrivez, et j'ai trouvé que ça marchait très bien.

Par défaut, un démon de serveur Pyro accepte les connexions de partout. Pour limiter cela, utilisez un validateur de connexion (voir documentation) ou fournissez host='127.0.0.1' au constructeur Daemon pour écouter uniquement les connexions locales.

code Exemple tiré de la documentation Pyro:

serveur

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

Un autre projet similaire est RPyC. Je n'ai pas essayé RPyC.

4

Vous pouvez l'associer à Pyro (http://pythonhosted.org/Pyro4/) l'objet distant Python. Il vous permet d'accéder à distance aux objets python. Il est facile à implémenter, a un faible coût et n'est pas aussi invasif que Twisted.

+0

Je pense que le lien que vous avez fourni pour Pyro est un autre pyro (un logiciel d'analyse thermodynamique), pas celui que vous pensez qu'il est (ou au moins est MAINTENANT). – ironstein

+0

Les choses changent en sept ans. J'ai mis à jour avec le repo actuel. – directedition