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

发布于 2024-07-15 22:08:20 字数 688 浏览 9 评论 0原文

我编写了一个作为守护进程运行的小型 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 比我现在想要的要多一些。 我想,下一个概念挑战是如何在不挂起工作线程的情况下与它们对话。

再次感谢。

I wrote a small Python application that runs as a daemon. It utilizes threading and queues.

I'm looking for general approaches to altering this application so that I can communicate with it while it's running. Mostly I'd like to be able to monitor its health.

In a nutshell, I'd like to be able to do something like this:

python application.py start  # launches the daemon

Later, I'd like to be able to come along and do something like:

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

To be clear, I don't have any problem implementing the Django-inspired syntax. What I don't have any idea how to do is to send signals to the daemonized process (start), or how to write the daemon to handle and respond to such signals.

Like I said above, I'm looking for general approaches. The only one I can see right now is telling the daemon constantly log everything that might be needed to a file, but I hope there's a less messy way to go about it.

UPDATE: Wow, a lot of great answers. Thanks so much. I think I'll look at both Pyro and the web.py/Werkzeug approaches, since Twisted is a little more than I want to bite off at this point. The next conceptual challenge, I suppose, is how to go about talking to my worker threads without hanging them up.

Thanks again.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

被你宠の有点坏 2024-07-22 22:08:20

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

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

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

示例代码取自 Pyro 文档:

Server

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

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

Yet another approach: use Pyro (Python remoting objects).

Pyro basically allows you to publish Python object instances as services that can be called remotely. I have used Pyro for the exact purpose you describe, and I found it to work very well.

By default, a Pyro server daemon accepts connections from everywhere. To limit this, either use a connection validator (see documentation), or supply host='127.0.0.1' to the Daemon constructor to only listen for local connections.

Example code taken from the Pyro documentation:

Server

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

Another similar project is RPyC. I have not tried RPyC.

陌若浮生 2024-07-22 22:08:20

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

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

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

What about having it run an http server?

It seems crazy but running a simple web server for administrating your
server requires just a few lines using web.py

You can also consider creating a unix pipe.

梦魇绽荼蘼 2024-07-22 22:08:20

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

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

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

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

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

Use werkzeug and make your daemon include an HTTP-based WSGI server.

Your daemon has a collection of small WSGI apps to respond with status information.

Your client simply uses urllib2 to make POST or GET requests to localhost:somePort. Your client and server must agree on the port number (and the URL's).

This is very simple to implement and very scalable. Adding new commands is a trivial exercise.

Note that your daemon does not have to respond in HTML (that's often simple, though). Our daemons respond to the WSGI-requests with JSON-encoded status objects.

命硬 2024-07-22 22:08:20

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

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

I would use twisted with a named pipe or just open up a socket. Take a look at the echo server and client examples. You would need to modify the echo server to check for some string passed by the client and then respond with whatever requested info.

Because of Python's threading issues you are going to have trouble responding to information requests while simultaneously continuing to do whatever the daemon is meant to do anyways. Asynchronous techniques or forking another processes are your only real option.

蓝戈者 2024-07-22 22:08:20
# 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 编写,请在此处查看示例代码。

# 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 can be written using xmlrpclib, check example code here.

寄与心 2024-07-22 22:08:20

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

Assuming you're under *nix, you can send signals to a running program with kill from a shell (and analogs in many other environments). To handle them from within python check out the signal module.

那伤。 2024-07-22 22:08:20

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

You could associate it with Pyro (http://pythonhosted.org/Pyro4/) the Python Remote Object. It lets you remotely access python objects. It's easily to implement, has low overhead, and isn't as invasive as Twisted.

日久见人心 2024-07-22 22:08:20

您可以使用multiprocessing管理器(https://docs.python.org/3/library/multiprocessing.html#managers" rel="nofollow noreferrer">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))

You can do this using multiprocessing managers (https://docs.python.org/3/library/multiprocessing.html#managers):

Managers provide a way to create data which can be shared between different processes, including sharing over a network between processes running on different machines. A manager object controls a server process which manages shared objects. Other processes can access the shared objects by using proxies.

Example server:

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

Example client:

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))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文