53

我编写了一个作为守护进程运行的小型 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 比我想咬的要多一点。我想,下一个概念上的挑战是如何在不挂断工作线程的情况下与我的工作线程交谈。

再次感谢。

4

8 回答 8

36

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

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

默认情况下,Pyro 服务器守护进程接受来自任何地方的连接。为了限制这一点,要么使用连接验证器(参见文档),要么提供host='127.0.0.1'Daemon构造函数以仅侦听本地连接。

取自 Pyro 文档的示例代码:

服务器

导入 Pyro.core

JokeGen 类(Pyro.core.ObjBase):
        def __init__(self):
                Pyro.core.ObjBase.__init__(self)
        def 笑话(自我,姓名):
                return "对不起"+name+",我不知道任何笑话。"

Pyro.core.initServer()
守护进程=Pyro.core.Daemon()
uri=daemon.connect(JokeGen(),"jokegen")

print "守护进程运行在端口:",daemon.port
print "对象的uri是:",uri

daemon.requestLoop()

客户

导入 Pyro.core

# 您必须更改下面的 URI 以匹配您自己的主机/端口。
笑话 = Pyro.core.getProxyForURI("PYROLOC://localhost:7766/jokegen")

打印笑话.joke("Irmen")

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

于 2009-03-18T12:57:31.757 回答
18

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

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

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

于 2009-03-18T04:22:00.497 回答
16

使用werkzeug并让你的守护进程包含一个基于 HTTP 的 WSGI 服务器。

您的守护程序有一组小型 WSGI 应用程序来响应状态信息。

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

这实现起来非常简单,并且非常可扩展。添加新命令是一项简单的练习。

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

于 2009-03-18T10:26:16.830 回答
9

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

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

于 2009-03-18T05:04:08.913 回答
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 编写,在此处查看示例代码。

于 2009-03-18T05:38:27.460 回答
5

假设您在 *nix 下,您可以使用killshell(以及许多其他环境中的类似物)向正在运行的程序发送信号。要从 python 中处理它们,请查看信号模块。

于 2009-03-18T04:47:33.040 回答
5

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

于 2009-03-18T13:58:35.977 回答
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))
于 2020-10-01T15:10:45.653 回答