与正在运行的python守护进程通信

时间:2009-03-18 04:09:32

标签: python daemon

我编写了一个作为守护进程运行的小型Python应用程序。它利用线程和队列。

我正在寻找改变此应用程序的一般方法,以便我可以在它运行时与之通信。大多数情况下,我希望能够监测其健康状况。

简而言之,我希望能够做到这样的事情:

python application.py start  # launches the daemon

稍后,我希望能够出现并执行以下操作:

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

要清楚,我在实现Django启发的语法时没有任何问题。我不知道该怎么做是将信号发送到守护进程(开始),或者如何编写守护进程来处理和响应这些信号。

就像我上面所说,我正在寻找一般方法。我现在唯一能看到的就是告诉守护进程不断记录文件可能需要的所有内容,但我希望这样做的方法不那么混乱。

更新:哇,很多很棒的答案。非常感谢。我想我会看看Pyro和web.py/Werkzeug的方法,因为Twisted比我想要咬一点点多一点。我想,下一个概念上的挑战是如何在不挂断它的情况下与我的工作线程进行交谈。

再次感谢。

8 个答案:

答案 0 :(得分:35)

另一种方法:使用Pyro(Python远程对象)。

Pyro基本上允许您将Python对象实例发布为可以远程调用的服务。我已经将Pyro用于你描述的确切目的,我发现它可以很好地工作。

默认情况下,Pyro服务器守护程序接受来自任何地方的连接。要限制此操作,请使用连接验证程序(请参阅文档),或者向host='127.0.0.1'构造函数提供Daemon以仅侦听本地连接。

来自Pyro文档的示例代码:

服务器

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

<强>客户端

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

另一个类似的项目是RPyC。我没有尝试过RPyC。

答案 1 :(得分:18)

让它运行http服务器怎么样?

看起来很疯狂但运行一个简单的网络服务器来管理你的 服务器只需几行使用web.py

您还可以考虑创建一个unix管道。

答案 2 :(得分:16)

使用werkzeug并使您的守护程序包含基于HTTP的WSGI服务器。

您的守护程序包含一组小型WSGI应用程序,用于响应状态信息。

您的客户端只是使用urllib2向localhost发出POST或GET请求:somePort。您的客户端和服务器必须就端口号(和URL)达成一致。

实现起来非常简单,而且可扩展性很强。添加新命令是一项微不足道的工作。

请注意,您的守护程序不必以HTML格式进行响应(但这通常很简单)。我们的守护进程使用JSON编码的状态对象响应WSGI请求。

答案 3 :(得分:9)

我会使用带有命名管道的扭曲或只是打开一个套接字。看一下echo服务器和客户端examples。您需要修改echo服务器以检查客户端传递的字符串,然后使用任何请求的信息进行响应。

由于Python的线程问题,您将无法响应信息请求,同时继续执行守护程序要执行的任何操作。异步技术或分支其他进程是您唯一真正的选择。

答案 4 :(得分: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()

客户端可以使用xmlrpclib编写,请查看示例代码here

答案 5 :(得分:5)

假设您在* nix下,您可以从shell(以及许多其他环境中的模拟)向{}运行程序发送信号。要在python中处理它们,请查看signal模块。

答案 6 :(得分:4)

您可以将它与Pyro(http://pythonhosted.org/Pyro4/)Python远程对象相关联。它允许您远程访问python对象。它易于实现,开销低,并且不像Twisted那样具有侵入性。

答案 7 :(得分:0)

您可以使用multiprocessing个管理器(https://docs.python.org/3/library/multiprocessing.html#managers)来做到这一点:

管理器提供了一种创建可以在不同进程之间共享的数据的方法,包括通过网络在不同机器上运行的进程之间共享。管理器对象控制管理共享对象的服务器进程。其他进程可以使用代理访问共享对象。

示例服务器:

from multiprocessing.managers import BaseManager

class RemoteOperations:
    def add(self, a, b):
        print('adding in server process!')
        return a + b

    def multiply(self, a, b):
        print('multiplying in server process!')
        return a * b

class RemoteManager(BaseManager):
    pass

RemoteManager.register('RemoteOperations', RemoteOperations)

manager = RemoteManager(address=('', 12345), authkey=b'secret')
manager.get_server().serve_forever()

示例客户端:

from multiprocessing.managers import BaseManager

class RemoteManager(BaseManager):
    pass

RemoteManager.register('RemoteOperations')
manager = RemoteManager(address=('localhost', 12345), authkey=b'secret')
manager.connect()

remoteops = manager.RemoteOperations()
print(remoteops.add(2, 3))
print(remoteops.multiply(2, 3))