Rails 上的 Ruby - 在前端对 js 异步进行长 api 调用和 return 值的最佳方式?

Ruby on Rails - Best way to asynchronously make long api calls and return values to js on the frontend?

我正在创建一个最多显示 9 个费率的搜索页面。在前端,我正在向我的 rails 应用程序发送一个请求,其中包含获取 9 个费率的必要数据。

在我的一个 rails 控制器中,我抓取网页以获取速率。这可能需要 2 到 15 秒之间的任何时间。

我希望 运行 所有 9 个请求都在后台运行,这样我就可以处理其他传入的请求。例如,用户可以进行搜索并显示建议的结果。

我正在尝试使用并发-ruby gem 和 Promises。 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 函数中,我调用了另一个 class 中的方法,BetterRateOverride.check_rate。当我同步 运行 相同的代码时,我能够成功调用上述方法,但是当我 运行 它是我现在的设置方式时,我的代码一旦到达此调用就会挂起。为什么会这样?

是否无法在后台线程中调用另一个 class 的方法?在后台线程中承诺 运行 吗?我在 ruby 全局线程池中阅读了 Promises 运行。

如果这不是最好的方法,你能指导我正确的方向吗?

感谢您的帮助。

编辑:我认为这可能是我的代码死锁的问题: https://github.com/rails/rails/issues/26847

解决此类问题的常规 Rails 方法是使用 ActiveJob 将长 运行 请求作为后台作业来实现。

每个费率请求都会在工作进程中触发一个单独的作业 运行,并且该作业会在完成后更新您在 DB(或 Redis)中的作业。

然后您将拥有另一个控制器,您的 JS 会轮询该控制器以检查各个作业的状态/结果。

除非您是 Rails 专家,否则我建议不要将 concurrent-ruby gem 与 Rails 一起使用,因为它会使事情变得非常复杂。

@fylooi 已经提供了一种常用方法 - 使用 ActiveJob 处理后台作业,并使用 JavaScript 轮询器检测它何时完成。您必须设置 ActiveJob 后端,这需要一些工作。

另一种解决方案是在 Rails 中保持完全同步,而在 JavaScript 中进行并行化。也就是说,您会 运行 多个 AJAX 并行请求。 (Max 6,但这对你的情况来说可能就足够了。)