Лучшая практика для обработки большого количества данных, пока пользователь ждет (в Rails)?

У меня есть букмарклет, который при использовании отправляет все URL-адреса на текущей странице браузера в приложение Rails 3 для обработки. За кулисами я использую Typhoeus, чтобы проверить, возвращает ли каждый URL-адрес код состояния 2XX. В настоящее время я инициирую этот процесс через запрос AJAX к серверу Rails и просто жду, пока он обрабатывает и возвращает результаты. Для небольшого набора это очень быстро, но когда количество URL достаточно велико, пользователь может ждать до, скажем, 10-15 секунд.

Я рассматривал возможность использования Delayed Job для обработки этого вне потока пользователя, но это не похоже на правильный вариант использования. Поскольку пользователю необходимо дождаться завершения обработки, чтобы увидеть результаты, а отложенное задание может занять до пяти секунд, прежде чем задание будет даже запущено, я не могу гарантировать, что обработка произойдет как можно скорее. К сожалению, это время ожидания неприемлемо.

В идеале, я думаю, должно получиться следующее:

  • Пользователь нажимает букмарклет
  • Данные отправляются на сервер для обработки
  • Ожидающая страница мгновенно возвращается при выделении потока для выполнения обработки.
  • Страница ожидания периодически опрашивает через ajax результаты обработки и обновляет страницу ожидания (например: «Обработано 4 из 567 URL-адресов...»).
  • страница ожидания обновляется результатами, как только они будут готовы

Некоторые дополнительные детали:

  • Я использую Heroku (длительные процессы убиваются через 30 секунд)
  • Эту функцию могут использовать как авторизованные, так и анонимные пользователи.

Это типичный способ сделать это, или есть лучший способ? Должен ли я просто запускать свою собственную внепотоковую обработку, которая обновляет БД во время обработки, или есть что-то вроде отложенной работы, которую я могу использовать для этого (и это работает на Heroku)? Любые толчки в правильном направлении будут высоко оценены.


person markquezada    schedule 09.11.2010    source источник
comment
Что ты сделал в итоге?   -  person Ari    schedule 07.08.2013
comment
@Ari, прошло много времени с тех пор, как я работал над этим, но в целом я использовал фоновый процессор (сегодня я бы использовал sidekiq) вместе с конечным автоматом, который отслеживал прогресс. Затем я просто опрашивал с помощью xhr на внешнем интерфейсе, пока состояние не было завершено или что вам нужно.   -  person markquezada    schedule 07.08.2013
comment
Спасибо. Итак, я думаю, Thread.new не будет работать сам по себе?   -  person Ari    schedule 07.08.2013


Ответы (1)


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

person Ben Lee    schedule 09.11.2010
comment
К счастью, Typhoeus обрабатывает URL-адреса параллельно, так что это намного быстрее, чем последовательно. Он также предоставляет обратный вызов on_complete, к которому я могу подключиться. (В настоящее время я использую его для кэширования результатов в memcache.) Я думаю, что я не могу понять следующее: как мне прикрепить эти данные к пользователю? Особенно если пользователь анонимный. Идентификатор сеанса, я полагаю? Я как бы не хочу, чтобы эти данные хранились в моей БД, если это анонимный пользователь. - person markquezada; 10.11.2010
comment
Похоже, у вас уже есть система на месте. Просто добавьте идентификатор сеанса к ключу (ключам), который вы установили в обработчиках Typhoeus on_complete. А затем в конечной точке опроса, которая обращается к этим ключам кэша памяти на основе идентификатора сеанса, может (после того, как все будет обработано и возвращено пользователю) удалить соответствующие ключи из базы данных. Но, основываясь на вашем комментарии, я уверен, что вы уже обдумали это и у вас есть некоторые проблемы с этим, но я на самом деле не понимаю, что это за проблема. - person Ben Lee; 10.11.2010
comment
Ах, наверное, я просто не додумался использовать memcache напрямую в качестве временного хранилища для готовых данных результатов. Сейчас я использую его только для кэширования результатов сканирования отдельных URL-адресов. (Не привязан к конкретному пользователю.) Но вы правы, я мог бы полностью использовать memcache для временного хранения полного результата запроса конкретного пользователя. Таким образом, он не будет засорять БД для анонимных пользователей, поскольку это не критические данные. (Он будет постоянно сохранен для зарегистрированных пользователей.) Отличная идея. Спасибо, что помогли мне это обдумать. - person markquezada; 10.11.2010