Ruby on Rails - лучший способ асинхронно выполнять длинные вызовы API и возвращать значения js на веб-интерфейсе? - PullRequest
1 голос
/ 08 июля 2019

Я создаю страницу поиска, которая отображает до 9 оценок.На веб-интерфейсе я отправляю запрос в мое приложение rails, которое содержит необходимые данные для получения 9 ставок.

В одном из моих контроллеров рельсов я сканирую веб-страницу, чтобы получить оценку.Это может занять от 2 до 15 секунд.

Я хотел бы выполнить все 9 запросов в фоновом режиме, чтобы я мог обрабатывать другие поступающие запросы. Например, пользователь может выполнить поиск, и отобразятся предложенные результаты.

Я пытаюсь использовать камень параллельного рубина с Обещаниями.Переменная cleaned_params - это массив данных, необходимых для выполнения запроса.Есть до 9 запросов данных.

Вот что у меня есть:

 tasks = cleaned_params.map { |request_data| 
    Concurrent::Promises.future(request_data) { |request_data| api_get_rate(request_data) }
  }

  # My tasks could still be in the pending state, all_promises is a new promise that will be fulfilled once all fo the inner promises have been fulfilled
  all_promises = Concurrent::Promises.zip(*tasks)

# Use all_promises.value! to block - I don't want to render a response until we have the rates. 
  render json: {:success => true, :status => 200, :rates => all_promises.value! }

Сейчас я вижу, что все запросы к api_get_rate запускаются, но внутри моей функции api_get_rate я вызываюметод в другом классе, BetterRateOverride.check_rate.Когда я выполняю этот же код синхронно, я успешно могу вызвать вышеупомянутый метод, но когда я запускаю его так, как я его сейчас настроил, мой код просто зависает, как только доходит до этого вызова.Почему это происходит?

Разве невозможно вызвать метод из другого класса в фоновом потоке?Обещания выполняются в фоновых потоках?Я читал, что Promises выполняются в глобальном пуле потоков ruby.

Если это не лучший подход, можете ли вы направить меня в правильном направлении?

Спасибо за любую помощь.

Редактировать: Я думаю, что это может быть проблемой дляблокировка моего кода: https://github.com/rails/rails/issues/26847

Ответы [ 2 ]

3 голосов
/ 08 июля 2019

Традиционный подход Rails к решению этой проблемы заключается в реализации долгосрочного запроса в качестве фонового задания с использованием ActiveJob.

Каждый запрос скорости запускает отдельное задание, выполняемое в рабочем процессе, и задание обновляет ваше задание в БД (или Redis) по завершении.

Затем у вас будет другой контроллер, который ваш JS опрашивает для проверки состояния / результатов отдельных заданий.

1 голос
/ 09 июля 2019

Если вы не являетесь экспертом по Rails, я бы рекомендовал не использовать gem concurrent-ruby вместе с Rails, так как это может усложнить задачу.

Один общий подход уже предоставлен @fylooi - использование ActiveJob дляобрабатывать фоновые задания и JavaScript-поллер, чтобы определить, когда он закончится.Вам придется настроить бэкэнд ActiveJob, что немного трудоемко.

Другое решение - полностью синхронизироваться в Rails и вместо этого выполнять распараллеливание в JavaScript.Т.е. вы будете выполнять несколько запросов AJAX параллельно.( Макс. 6 , но этого может быть достаточно для вашего случая.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...