Асинхронное повторение ответа на запрос с помощью Thin и Sinatra


Если ваш ответ в Sinatra возвращает объект "eachable", цикл событий Sinatra будет "каждый" ваш результат и выдаст результаты потоковым способом в виде HTTP-ответа. Однако, если есть параллельные запросы к Sinatra, он будет перебирать все элементы одного ответа, прежде чем обрабатывать другой запрос. Если у нас есть курсор на результаты некоторого запроса БД, это означает, что мы должны ждать, пока все данные будут доступны, прежде чем обрабатывать параллельный запрос.

Я посмотрел в асинхронном-Синатра джем и http://macournoyer.com/blog/2009/06/04/pusher-and-async-with-thin/, думая, что это решит мою проблему, но я попробовал этот пример:

require 'sinatra/async'

class AsyncTest < Sinatra::Base
  register Sinatra::Async

  aget '/' do
    body "hello async"
  end

  aget '/delay/:n' do |n|
    EM.add_timer(n.to_i) { body { "delayed for #{n} seconds" } }
  end
end

И /delay/5 запрос не работает одновременно, как я ожидаю, то есть я делаю 3 запроса одновременно, и отладчик Chrome отмечает время отклика примерно 5, 10 и 15 секунд.

Я пропустил какую-то настройку или есть другой способ сказать Sinatra / Thin обрабатывать запросы одновременно образом?

Обновление: вот еще один ключ в этом (или, возможно, проясняет вещи): Запуск curl -i http://localhost:3000/delay/5 одновременно имеет правильное поведение (2 запроса каждый возвращаются через ~5 секунд). Запуск ab -c 10 -n 50 http://locahost:3000/delay/5 (утилита Apache benchmark) также возвращает что-то разумное за общее время (~25 секунд). Firefox демонстрирует то же поведение, что и Chrome. Чем браузеры отличаются от утилит командной строки?

2 4

2 ответа:

Таким образом, в конце концов, я обнаружил, что пример действительно работает, и я мог бы в конечном итоге заставить Синатру передавать каждый из возможных результатов одновременно, в основном используя идею EM.defer в Pusher и Async page. Curl и Apache benchmarking подтвердили, что это работает.

Причина, по которой он не работал в браузере, заключается в том, что браузеры ограничивают количество подключений к одному и тому же URL. Я знал, что существует ограничение на одновременные подключения к одному домену (также низкое число), но не что (по-видимому) все соединения с одним URI сериализованы:

Http://maillist.caucho.com/pipermail/resin-interest/2009-August/003998.html

Я не знаю, можно ли это настроить, я вижу только доменную конфигурацию в Firefox, но это было проблемой.

Когда вы собираетесь обработать ответ объекта, сделайте следующее:

fork do
  handle request...
  exit 99
end

И если вам не нужно, не ждите окончания этого дочернего процесса.. с a:

child = fork do
  handle request...
  exit 99
end

Process.detach(child)

Это простой способ обработки нескольких запросов, однако я не уверен, что ORM вы можете использовать для этих запросов БД, но вы можете попасть в проблемы блокировки уровня таблицы/строки с несколькими процессами, пытающимися попасть в БД, если это то, что вы имеете в виду, когда говорите об обработке запросов...