如何将SIGUSR1处理程序添加到Twisted程序?

时间:2017-03-19 22:34:21

标签: python linux twisted

我正在寻找一种方法来检查基于Twisted的程序的状态,因此我可以确定连接的客户端的数量,并查看我收集的其他指标(例如连接建立的时间或时间)最后联系)。

我的想法是为进程添加SIGUSR1的信号处理程序,这样当进程收到它时,它会将状态转储到已知位置的文件中。这有几个问题:

  • Twisted使用自己的处理程序覆盖信号处理程序,因为当信号到达时,进程以&#34结束;用户信号1收到"在stdout上,我的代码未被调用
  • 考古研究on a mailing list显示Twisted不会覆盖SIGINT的处理程序;但事实并非如此(Python 2.7.11与Twisted 16.1.1),该过程退出" KeyboardInterrupt"在stdout
  • 其他资源建议reactor.run(installSignalHandlers=False)reactor.run(installSignalHandlers=0),但这似乎没有效果。

因此我有几个问题:

  1. 处理信号的思想正确方法是什么? (如果可能的话)
  2. 实施此类"状态内省"的推荐方法是什么? Twisted服务器的设施? (我正在考虑让它在另一个端口上侦听TCP连接,并将其用作POSIX信号的替代方案 - 但我觉得我的事情太复杂了。)
  3. 感谢您抽出宝贵时间阅读本文,我期待着这个星球的蜂巢头脑的暗示。

    这是邮件列表的相关摘录:

    > If you do this, you'll break spawnProcess.  Fortunately, if you just
    > install a SIGINT handler, Twisted won't stomp on it:
    >    exarkun at charm:~$ python
    >    Python 2.5.2 (r252:60911, Jul 31 2008, 17:28:52)    [GCC 4.2.3 
    > (Ubuntu 4.2.3-2ubuntu7)] on linux2
    >    Type "help", "copyright", "credits" or "license" for more information.
    >    >>> def f(*a):
    >    ...     print 'sigint'
    >    ...    >>> import signal
    >    >>> signal.signal(signal.SIGINT, f)
    >    
    >    >>> from twisted.internet import reactor
    >    >>> reactor.run()
    >    sigint
    >    sigint
    >    sigint
    >    Quit
    

1 个答案:

答案 0 :(得分:2)

从Twisted 17.1开始,只有twistd安装SIGUSR1处理程序,如果您已经为该信号安装了处理程序,它将跳过安装。

将SIGUSR1发送到流程时在stdout上看到的消息:

user signal 1 received

是OS 默认系统处理程序。该默认值的行为是退出该进程。这表明您和Twisted都没有为SIGUSR1安装处理程序。当您认为正在运行并且您没有使用twistd时,您的处理程序安装代码似乎没有运行。

...然而

  

处理信号的思想正确方法是什么? (如果可能的话)

很可能根本不可能。信号是一个兔子洞。如果您对此事有任何选择,请远离它们。将异步信号传递引入任何Python程序是非常充实的。在某些情况下,可能可以正确可靠地进行,但我不会赌它。信号与多线程的交互很复杂,因为POSIX的缺点和Python在这些基础上增加了额外的复杂性。信号处理程序是一个共享的全局资源(正如您所指出的那样),因此不同代码库之间的复杂交互尝试使用它们。

最后,您可以使用各种各样的替代方案来解决这些问题。

  

为Twisted服务器实施这种“状态内省”设施的推荐方法是什么? (我正在考虑让它在另一个端口上侦听TCP连接,并将其用作POSIX信号的替代方案 - 但我觉得我的事情太复杂了。)

使用除POSIX信号以外的机制可能看起来更复杂,但我建议它更简单,但可能需要更多的输入。

我没有“状态内省”的一般提案,但这是针对此案例的具体提案:在您的流程中添加HTTP服务器。

这是一个直截了当的例子:

from json import dumps

from twisted.web.server import Site
from twisted.web.resource import Resource
from twisted.internet.endpoints import serverFromString

class StateResource(Resource):
    def render(self, request):
        return dumps({"your": "state info"})

root = Resource()
root.putChild(b"", StateResource())
serverFromString("tcp:12345").listen(Site(root))

是的,它比等效的基于信号的代码长10行。但是,它没有奇怪的多线程或多进程交互。它独立于平台。它不会踩踏共享资源(也不会被踩踏) - 除了我随机挑选的那个tcp端口(如果你不喜欢它,你可以在UNIX套接字上运行它 - 同时授予访问控制权限) ,如果这对你很重要。)

真正开始变得显而易见时,优秀的解决方案就是当您想要为您的应用程序添加运行状况检查时,您的主管可以监控它。然后,您需要添加度量标准报告器,以便您的监控系统可以提取该数据并将其呈现给您的SRE或运营团队。等等。基于信号的解决方案可以处理这些额外的功能变得更加复杂,我怀疑,最终总SLOC数量高于HTTP解决方案。即,HTTP服务器可以很好地适应新的功能要求。基于信号的解决方案没有。

相关问题