Витой вызов клиента из библиотечной функции

Я пытаюсь реализовать функцию, которая будет действовать как клиент 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 исключение.

Другие вопросы по тегам