Витой вызов клиента из библиотечной функции
Я пытаюсь реализовать функцию, которая будет действовать как клиент Twisted. Он вызывается из кода, который я не контролирую. Я пробовал что-то вроде (это взято из примера кода pbsimpleclient.py):
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
from twisted.spread import pb
from twisted.internet import reactor
from twisted.python import util
def remcall(**kw):
factory = pb.PBClientFactory()
reactor.connectTCP("localhost", 8789, factory)
d = factory.getRootObject()
# kw here is what's passed in via remcall
d.addCallback(lambda object: object.callRemote("echo", kw))
d.addCallback(lambda echo: 'server echoed: '+repr(echo))
d.addErrback(lambda reason: 'error: '+str(reason.value))
d.addCallback(util.println)
d.addCallback(lambda _: reactor.stop())
reactor.run()
И звонящий звонит так:
remcall(hello=1, world=2)
remcall(hi=3, there=4)
Но, как вы уже догадались, выдает ошибку "twisted.internet.error.ReactorNotRestartable".
Какой лучший способ сделать это? Я не очень беспокоюсь о получении ответа от удаленного конца, но я должен знать, если он терпит неудачу и почему.
2 ответа
Ответ заключается в использовании крючком.
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
## Add these two lines
from crochet import setup, wait_for
setup()
from twisted.spread import pb
from twisted.internet import reactor
from twisted.python import util
## Add a wait_for decorator
@wait_for(timeout=5.0)
def remcall(**kw):
factory = pb.PBClientFactory()
reactor.connectTCP("localhost", 8789, factory)
d = factory.getRootObject()
# kw here is what's passed in via remcall
d.addCallback(lambda object: object.callRemote("echo", kw))
d.addCallback(lambda echo: 'server echoed: '+repr(echo))
d.addErrback(lambda reason: 'error: '+str(reason.value))
d.addCallback(util.println)
## Get rid of the reactor calls, and return d
# d.addCallback(lambda _: reactor.stop())
# reactor.run()
return d
Тогда звонящий просто звонит
remcall(hello=1, world=2)
remcall(hi=3, there=4)
и @wait_for вязания крючком, выполняющие remcall внутри потока реактора.
Удалить reactor.run()
от remcall
функция и добавить его в конце. Также удалите d.addCallback(lambda _: reactor.stop())
def remcall(**kw):
factory = pb.PBClientFactory()
reactor.connectTCP("localhost", 8789, factory)
d = factory.getRootObject()
# kw here is what's passed in via remcall
d.addCallback(lambda object: object.callRemote("echo", kw))
d.addCallback(lambda echo: 'server echoed: '+repr(echo))
d.addErrback(lambda reason: 'error: '+str(reason.value))
d.addCallback(util.println)
remcall(hello=1, world=2)
remcall(hi=3, there=3)
reactor.run() # this should be the last thing to run
Реактор может работать только один раз. reactor.stop()
Функция выполняется, и это не должно происходить, если ваше приложение не должно полностью прекратить работу. Вот почему вы получаете ReactorNotRestartable
исключение.