Асинхронная итерация ответа на запрос с использованием Thin и Sinatra - PullRequest
4 голосов
/ 16 октября 2010

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

Я посмотрел на гем async-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 <a href="http://localhost:3000/delay/5" rel="nofollow">http://localhost:3000/delay/5</a> одновременно ведет к правильному поведению (2 запроса каждый возвращается через ~ 5 секунд).Запуск ab -c 10 -n 50 <a href="http://locahost:3000/delay/5" rel="nofollow">http://locahost:3000/delay/5</a> (утилита тестирования Apache) также возвращает что-то разумное для общего времени (~ 25 секунд).Firefox демонстрирует то же поведение, что и Chrome.Чем браузеры отличаются от утилит командной строки?

Ответы [ 2 ]

4 голосов
/ 10 ноября 2010

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

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

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

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

0 голосов
/ 16 октября 2010

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

fork do
  handle request...
  exit 99
end

и если вам не нужно ждать, пока этот дочерний процесс не завершится .. с помощью:

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

Process.detach(child)

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

...