@kawashirov

Как сделать «продолжительные» эвенты на Python Tornado?

Объясню на примере. Я пишу TCP прокси сервер для одной игры, он не только обрабатывает пакеты, но и шлет от имени игры различные запросы для сбора статистики, иногда сам отвечает вместо игры. Суть в том, что это всё настолько разрослось, что я решил сделать простенькую систему плагинов и разбить всю логику обработки сообщений на множество плагинов.

Тогда типичный плагин, если всё упростить, начинает выглядеть так:
class SimplePlugin:
  @coroutine
  def on_request_from_client(self, event):
    чё-то делаем с запросом
  @coroutine
  def on_response_from_server(self, event):
    чё-то делаем с ответом


Проблема в том, что контекст "разбит" между двумя методами и если плагину нужно обработать определенный ответ на определенный запрос, приходится сохранять всё в self и потом каждый ответ рассматривать и определять на какой запрос он пришел, восстанавливать контекст. Это неудобно до жути. Совсем не pythonic way. Хотелось бы видеть что-то такое:
class SimplePlugin:
  @coroutine
  def on_request_from_client(self, event):
    чё-то делаем с запросом
    yield event.wait_for_response()
    чё-то делаем с ответом

Т.е. "движок" плагинов пускает эвент запроса в плагины, поочередно. Если выбрасывается "хочу подождать ответа", то идет к следующему плагину, накапливая все "хотелки". Далее, когда обработка запросов завершена, он пускает запрос на сервер, ловит ответ, и далее начинает поочередно возвращать ответ в сопрограммы с хотелками, что бы они продолжили обработку ответа. По идее такой цикл можно увеличивать бесконечно типа event.хочу_то(), event.хочу_это()

Знающие люди, возможно, заметят, что можно сделать так:
class SimplePlugin:
  @coroutine
  def on_request_from_client(self, event):
    чё-то делаем с запросом
    def callback():
      чё-то делаем с ответом
    IOLoop.add_future(event.response_future, callback)

Но тут есть пара проблем. Во-первых, сразу после того, как "движок" получит ответ и разрешит event.response_future, то все callbackи запустятся "параллельно". Ну т.е. они исполняться будут, конечно, последовательно, но если один callback делает что-то тяжелое в плане I/O, он прерывается и начинает исполняться следующий. Т.е. первый еще не закончил, а второй уже начался. Значит нужно обмазываться Lockами и т.п. Уже не всё просто. А во-вторых опять же это не совсем pythonic way, и уж точно не tornado way.

Пока что я изучаю сорцы торнадо и думаю над тем, что бы сделать свою реализацию @coroutine для данного случая.
  • Вопрос задан
  • 324 просмотра
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы