Twisted PerspectiveBroker callRemote из веб-приложения wsgi - PullRequest
1 голос
/ 22 января 2012

Я пишу wsgi приложение, которое должно использовать Twisted PerspectiveBroker для вызова некоторых удаленных методов. Проблема в том, что wsgi должен возвращать отображаемую веб-страницу, но вызовы службы Twisted являются асинхронными. Поэтому в основном моему веб-приложению необходимо вызывать удаленные методы, затем делать какие-то другие вещи, затем ждать окончания удаленных вызовов, затем обрабатывать страницу и возвращать ее клиенту.

Каков наилучший способ сделать это?

В настоящее время я планирую использовать Flask для написания приложения.

Ответы [ 2 ]

4 голосов
/ 22 января 2012

Приложение WSGI работает в своем собственном потоке (или процессе). При работе в контейнере WSGI Twisted это поток, отличный от потока, в котором работает реактор. Большинство API Twisted не являются поточно-ориентированными: их можно вызывать только в потоке реактора.

Итак, основной способ вызова Twisted API из приложения WSGI - это использование reactor.callFromThread, которое является поточно-ориентированным и вызывает функцию, вызываемую в потоке реактора:

...
reactor.callFromThread(pbRemote.callRemote, "someMethod", some, args)

Однако, это отбрасывает результат, который вы, вероятно, хотите. Однако просто построить API поверх reactor.callFromThread, который сохраняет результат, и есть реализация этого и в Twisted:

from twisted.internet.threads import blockingCallFromThread

...
result = blockingCallFromThread(reactor, pbRemote.callRemote, "someMethod", some, args)

Этот вызов будет блокироваться до тех пор, пока не сработает Отложенный, возвращенный callRemote, а затем вернет результат этого Отложенного.

Если вы хотите позвонить, сделать какую-то другую работу, а затем дождаться окончания разговора, вам нужно проявить немного творчества. Вам нужно сделать вызов и получить фактический Deferred, который он возвращает, но не блокировать его:

resultHolder = blockingCallFromThread(
    reactor, lambda: [pbRemote.callRemote("someMethod", some, args)])

И тогда вы можете делать то, что вам нужно. И когда вы будете готовы дождаться результата вызова PB:

result = blockingCallFromThread(reactor, lambda: resultHolder[0])

Это все гораздо более неловко, чем использование Twisted в однопоточном сценарии, поэтому действительно может быть проще использовать собственные API-интерфейсы Twisted Web, а не создавать приложение WSGI. Помните, что одна из основных целей WSGI - разрешить разработку приложений, переносимых на разные серверы - Twisted, Apache и т. Д. Если вы действительно используете Twisted API в своем приложении WSGI, то он вообще не переносим.

1 голос
/ 22 января 2012

Вы можете вернуть server.NOT_DONE_YET, чтобы сообщить twisted.web, что запрос не завершен. А затем вызовите request.write () и request.finish (), чтобы завершить запрос позже, например:

from twisted.web import server, resource

class MyResource(resource.Resource):
    def render_GET(self, request):
        # the call will return defer, that will notify us when it finish
        d = delayCall()
        # finish the request
        def finisn_req(data):
            request.write(data)
            request.finish()
        d.addCallback(finisn_req)
        # tell twisted.web that this request is not finished, yet
        return server.NOT_DONE_YET
...