如何优雅地退出以 twistd 开头的应用程序?
Posted
技术标签:
【中文标题】如何优雅地退出以 twistd 开头的应用程序?【英文标题】:How to gracefully exit application started with twistd? 【发布时间】:2011-03-17 19:23:34 【问题描述】:我有一个 jabber 客户端,它正在读取其标准输入并发布 PubSub 消息。如果我在标准输入上得到 EOF,我想终止客户端。
我首先尝试了sys.exit()
,但这会导致异常并且客户端不会退出。然后我做了一些搜索,发现我应该打电话给reactor.stop()
,但我无法完成这项工作。我的客户端中的以下代码:
from twisted.internet import reactor
reactor.stop()
exceptions.AttributeError: 'module' object has no attribute 'stop'
中的结果
我需要做什么才能让twistd 关闭我的应用程序并退出?
编辑 2
最初的问题是由一些符号链接弄乱了模块导入引起的。解决该问题后,我得到了一个新异常:
twisted.internet.error.ReactorNotRunning: Can't stop reactor that isn't running.
异常后,twistd 关闭。我认为这可能是由在MyClient.connectionInitialized
中调用MyClient.loop
引起的。也许我需要把电话推迟到以后?
编辑
这是我的客户的 .tac
文件
import sys
from twisted.application import service
from twisted.words.protocols.jabber.jid import JID
from myApp.clients import MyClient
clientJID = JID('client@example.com')
serverJID = JID('pubsub.example.com')
password = 'secret'
application = service.Application('XMPP client')
xmppClient = client.XMPPClient(clientJID, password)
xmppClient.logTraffic = True
xmppClient.setServiceParent(application)
handler = MyClient(clientJID, serverJID, sys.stdin)
handler.setHandlerParent(xmppClient)
我正在调用它
twistd -noy sentry/myclient.tac < input.txt
这是 MyClient 的代码:
import os
import sys
import time
from datetime import datetime
from wokkel.pubsub import PubSubClient
class MyClient(PubSubClient):
def __init__(self, entity, server, file, sender=None):
self.entity = entity
self.server = server
self.sender = sender
self.file = file
def loop(self):
while True:
line = self.file.readline()
if line:
print line
else:
from twisted.internet import reactor
reactor.stop()
def connectionInitialized(self):
self.loop()
【问题讨论】:
【参考方案1】:from twisted.internet import reactor
reactor.stop()
应该工作。事实上,这并不意味着您的应用程序有其他问题。我无法从您提供的信息中找出问题所在。
能否提供更多(全部)代码?
编辑:
好的,现在的问题是你没有停止自己的while True
循环,所以它会继续循环并最终再次停止反应器。
试试这个:
from twisted.internet import reactor
reactor.stop()
return
现在,我怀疑您的循环对于事件驱动框架来说并不是一件好事。虽然您只是打印行,但这很好,但取决于您真正想要做什么(我怀疑您会做的不仅仅是打印行),您必须重构该循环以处理事件。
【讨论】:
确实如此。当您停止反应器时,就该退出该过程了。【参考方案2】:使用reactor.callFromThread(reactor.stop)
代替reactor.stop
。这应该可以解决问题。
【讨论】:
这救了我。谢谢。 我也必须以同样的方式包装我的 reactor.run。reactor.callFromThread(reactor.run)
【参考方案3】:
我曾经这样做过(在非扭曲调用应用程序的 sigint 处理程序中):
reactor.removeAll()
reactor.iterate()
reactor.stop()
我不是 100% 确定这是正确的方式,但扭曲是快乐的
在 tac 中启动的同一个应用程序直接由 twistd 信号处理程序处理,我发现了这个问题,因为我有一些 rpc 客户端请求,我会在退出之前等待并处理结果,看起来 twistd 只是在杀死反应堆没有让调用结束
【讨论】:
致电reactor.iterate()
几乎不是一个好主意。而且在反应堆运行时调用它是不正确的(在这个例子中它必须是,因为reactor.stop()
是之后调用的)。
reactor.stop() 还不够,可能我的应用有问题,但是需要remove + iterate + stop 来避免扭曲的抱怨,所以我应该只调用stop()?跨度>
击败我。我对你的申请一无所知。但我知道这样称呼iterate
是不正确的。以上是关于如何优雅地退出以 twistd 开头的应用程序?的主要内容,如果未能解决你的问题,请参考以下文章
如何将systemd作为非特权用户部署Twistd https应用程序(.tac)?