Как изящно выйти из приложения, запущенного с помощью twistd?
У меня есть jabber-клиент, который читает из своего stdin и публикует сообщения PubSub. Если я получаю EOF на stdin, я хочу завершить работу с клиентом.
Сначала я попробовал 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.loop
в MyClient.connectionInitialized
. Возможно, мне нужно отсрочить вызов до следующего?
ИЗМЕНИТЬ
Здесь .tac
файл для моего клиента
import sys
from twisted.application import service
from twisted.words.protocols.jabber.jid import JID
from myApp.clients import MyClient
clientJID = JID('[email protected]')
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()
который должен работать. Тот факт, что это не означает, что что-то еще не так в вашем приложении. Я не могу понять, что неправильно из предоставленной вами информации.
Можете ли вы предоставить больше (всего) кода?
EDIT:
Хорошо, теперь проблема заключается в том, что вы не останавливаете свой собственный цикл while True
, поэтому он будет продолжать цикл и в конечном итоге снова останавливать реактор.
Попробуйте следующее:
from twisted.internet import reactor
reactor.stop()
return
Теперь я подозреваю, что ваш цикл не очень хорош для фреймворка, управляемого событиями. Пока вы просто печатаете строки, это нормально, но в зависимости от того, что вы действительно хотите сделать (я подозреваю, что вы сделаете больше, чем просто строк печати), вам придется реорганизовать этот цикл для работы с событиями.
Ответ 2
Используйте reactor.callFromThread(reactor.stop)
вместо reactor.stop
. Это должно решить проблему.
Ответ 3
Я использовал этот способ (в sigint-обработчике не-twistd-приложения):
reactor.removeAll()
reactor.iterate()
reactor.stop()
Я не уверен на 100%, что это правильный путь, но скрученный счастлив
одно и то же приложение, запущенное в tac, обрабатывается непосредственно обработчиком сигнала twistd, я нашел этот вопрос, потому что у меня есть некоторые клиентские запросы rpc, которые я должен был ждать и обрабатывать результат перед выходом и выглядит как twistd, просто убивая реактор, не позволяя завершить вызов