Python, Twisted, Django, реактор.run() вызывает проблемы
У меня есть веб-приложение Django. У меня также есть сервер заклинаний, написанный с использованием витой, работающей на той же машине, на которой работает django (работает на localhost:8090
). Идея заключается в том, что когда пользователь выполняет какое-либо действие, запрос поступает в Django, который, в свою очередь, подключается к этому витому серверу, а сервер отправляет данные обратно в Django. Наконец, Django помещает эти данные в некоторый HTML-шаблон и возвращает их пользователю.
Вот где у меня проблема. В моем приложении Django, когда приходит запрос, я создаю простой витой клиент для подключения к локально работающему витому серверу.
...
factory = Spell_Factory(query)
reactor.connectTCP(AS_SERVER_HOST, AS_SERVER_PORT, factory)
reactor.run(installSignalHandlers=0)
print factory.results
...
reactor.run()
вызывает проблему. Так как это цикл событий. В следующий раз, когда Джанго выполнит этот код, я не смогу подключиться к серверу. Как с этим справиться?
3 ответа
Приведенные выше два ответа верны. Однако, учитывая, что вы уже внедрили сервер орфографии, запустите его как один. Вы можете начать, запустив его на той же машине, что и отдельный процесс - в localhost:PORT
, Сейчас кажется, что у вас уже есть очень простой интерфейс двоичного протокола - вы можете реализовать такой же простой клиент Python, используя стандартные библиотеки socket
интерфейс в режиме блокировки.
Тем не менее, я предлагаю поиграть с twisted.web
и выставить простой веб-интерфейс. Вы можете использовать JSON для сериализации и десериализации данных - что хорошо поддерживается Django. Вот очень быстрый пример:
import json
from twisted.web import server, resource
from twisted.python import log
class Root(resource.Resource):
def getChild(self, path, request):
# represents / on your web interface
return self
class WebInterface(resource.Resource):
isLeaf = True
def render_GET(self, request):
log.msg('GOT a GET request.')
# read request.args if you need to process query args
# ... call some internal service and get output ...
return json.dumps(output)
class SpellingSite(server.Site):
def __init__(self, *args, **kwargs):
self.root = Root()
server.Site.__init__(self, self.root, **kwargs)
self.root.putChild('spell', WebInterface())
И чтобы запустить его, вы можете использовать следующий скелет .tac
файл:
from twisted.application import service, internet
site = SpellingSite()
application = service.Application('WebSpell')
# attach the service to its parent application
service_collection = service.IServiceCollection(application)
internet.TCPServer(PORT, site).setServiceParent(service_collection)
Запуск вашего сервиса в качестве другого первоклассного сервиса позволяет вам запускать его на другом компьютере в один прекрасный день, если вы обнаружите в этом необходимость - использование веб-интерфейса позволяет легко масштабировать его по горизонтали за балансировщиком нагрузки с обратным проксированием.
reactor.run()
должен вызываться только один раз во всей вашей программе. Не думайте об этом как о "начните этот запрос, который у меня есть", думайте об этом как "начните все с Twisted".
Работа реактора в фоновом режиме - один из способов обойти это; тогда ваше приложение django может использовать blockingCallFromThread
в вашем приложении Django и используйте Twisted API, как любой другой блокирующий API. Однако вам понадобится немного сотрудничества с вашим контейнером WSGI, потому что вам нужно будет убедиться, что этот фоновый витой поток запускается и останавливается в подходящее время (когда ваш интерпретатор инициализируется и срывается, соответственно).
Вы также можете использовать Twisted в качестве контейнера WSGI, и тогда вам не нужно запускать или останавливать что-то особенное; blockingCallFromThread
будет просто работать сразу. См. Справку командной строки для twistd web --wsgi
,
Вы должны остановить реактор после того, как вы получили результаты с сервера Twisted или произошла ошибка / тайм-аут. Таким образом, при каждом запросе Django, который требует запроса к вашему серверу Twisted, вы должны запустить реактор и затем остановить его. Но это не поддерживается библиотекой Twisted - реактор не перезапускается. Возможные решения:
Используйте отдельный поток для Twisted реактора, но вам нужно будет развернуть ваше приложение django с сервером, который поддерживает долго работающие потоки (сейчас у меня нет ни одного из них, но вы можете легко написать свой собственный:-)).
Не используйте Twisted для реализации клиентского протокола, просто используйте обычный stdlib
socket
модуль.