服务器在等待外部 api 响应时挂起所有请求
我正在使用 discogs-wrapper
gem 访问一些音乐信息,但我注意到在 api 请求期间服务器仍然静止,没有提供其他请求,其行为类似于调试器功能。我相信当我调用函数 Discogs::Artist.find_by_name name
时,实际的请求是在 gem 的以下部分触发的。
Net::HTTP.new(uri.host).start do |http|
http.request(request)
end
在两个不同的浏览器(chrome 和 firefox)中跟踪两个请求的日志,我首先运行对艺术家“pink floyd”的搜索,然后在另一个浏览器中刷新根页面,最后一个简单的请求通常需要几毫秒,在api 请求的时间与请求持续的时间一样长。
Started GET "/artists/show?utf8=%E2%9C%93&artist_name=pink+floyd&commit=search" for 127.0.0.1 at 2012-01-21 18:03:52 +0000
Processing by ArtistsController#show as HTML
Parameters: {"utf8"=>"✓", "artist_name"=>"pink floyd", "commit"=>"search"}
get_artist(pink floyd)
get_artist(pink floyd) - ended in 26394ms
Rendered artists/_search_form.html.haml (4.3ms)
Rendered discogs/artist/releases/_release.html.haml (606.5ms)
Rendered artists/show.html.haml within layouts/application (1876.4ms)
Completed 200 OK in 28303ms (Views: 1907.8ms | ActiveRecord: 0.0ms)
Started GET "/" for 127.0.0.1 at 2012-01-21 18:04:20 +0000
Processing by ApplicationController#show as HTML
Rendered artists/_search_form.html.haml (4.5ms)
Rendered application/show.html.haml within layouts/application (6.5ms)
Completed 200 OK in 23ms (Views: 22.0ms | ActiveRecord: 0.0ms)
如何避免服务器因可能需要 30 秒以上的响应而无用地挂起? - 谢谢
I am using discogs-wrapper
gem to access some music information, but I noticed that during the api request the server stills, no other requests are served, with a behavior similar to the debugger function. I believe the actual request is triggered in the following part of the gem, when I call the function Discogs::Artist.find_by_name name
.
Net::HTTP.new(uri.host).start do |http|
http.request(request)
end
Follows the log for two requests in two different browser (chrome and firefox), I first run the search for the artist "pink floyd" and then refreshed the root page in the other browser, this last simple request that usually takes milliseconds, during the api request takes as long as the request lasts.
Started GET "/artists/show?utf8=%E2%9C%93&artist_name=pink+floyd&commit=search" for 127.0.0.1 at 2012-01-21 18:03:52 +0000
Processing by ArtistsController#show as HTML
Parameters: {"utf8"=>"✓", "artist_name"=>"pink floyd", "commit"=>"search"}
get_artist(pink floyd)
get_artist(pink floyd) - ended in 26394ms
Rendered artists/_search_form.html.haml (4.3ms)
Rendered discogs/artist/releases/_release.html.haml (606.5ms)
Rendered artists/show.html.haml within layouts/application (1876.4ms)
Completed 200 OK in 28303ms (Views: 1907.8ms | ActiveRecord: 0.0ms)
Started GET "/" for 127.0.0.1 at 2012-01-21 18:04:20 +0000
Processing by ApplicationController#show as HTML
Rendered artists/_search_form.html.haml (4.5ms)
Rendered application/show.html.haml within layouts/application (6.5ms)
Completed 200 OK in 23ms (Views: 22.0ms | ActiveRecord: 0.0ms)
How can I avoid the server to hang uselessly for a response that could take even more than 30 secs? - thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您不想在请求/响应周期中执行任何可能像这样挂起的操作。理想情况下,Rails 应用程序中的所有操作都应尽快返回。
此问题的常见解决方案是将长时间运行的代码移至单独的后台作业进程。我不会尝试在单个 Rails 进程中分叉或运行多个线程之类的事情。
我目前推荐的两种流行的后台处理解决方案是:
存在其他解决方案后台作业解决方案,但在我看来,这是两个最流行的解决方案。
为了向用户反馈后台作业已完成,我想到了几个选项。
使用 AJAX 轮询服务器以查看作业何时完成。对于 resque,有许多插件可以帮助完成此任务: https://github.com/quirkey/ resque-status 或 https://github.com/idris/resque-progress例如。我认为如果工作能够相对较快地完成的话,这是简单且合适的。另外,我不会太频繁地进行 ajax 调用。这取决于您的服务器响应时间和负载,但我不会比一两秒更频繁地执行此操作。如果您的服务器速度缓慢或负载过重,这种轮询会使情况变得更糟。
使用推送技术。我发现 Juggernaut 非常易于使用。当作业完成后,将消息推送给客户端。然而,支持这一点的基础设施要复杂得多。但它消除了 Rails 服务器的轮询负载,并且推送技术可用于实现各种其他很酷的事情:)
You don't want to do anything in the request/response cycle that can hang like that. Ideally, all actions in your Rails app should return as fast as possible.
The common solution to this problem is to move the long-running code to a separate background job process. I would not attempt anything like forking or running multiple threads in a single rails process.
The two popular background processing solutions I would recommend at this time are:
Other solutions background job solutions exist, but these are the two most popular ones, IMO.
To give feedback to the user that a background job has completed, a couple of options come to mind.
Use AJAX to poll the server to see when the job is done. For resque, there are a number of plugins that can help accomplish this: https://github.com/quirkey/resque-status or https://github.com/idris/resque-progress for example. I think this is simple and appropriate if the job will finish relatively quickly. Also, I wouldn't make the ajax call too frequently. It would depend on your server response times and load, but I wouldn't do it any more frequently than a second or two. If your server is slow or heavily loaded, this polling will make it worse.
Use push technology. I've found Juggernaut to be super easy to use. When the job is complete, push the message to the client. The infrastructure to support this is considerably more complex, however. But it remove the load of polling from the rails server and push technology can be used to implement all kinds of other cool things :)
这就是 Rails 默认的工作方式:每个应用程序实例一次处理一个请求。您可以打开多线程模式(
config.threadsafe!
),thin 应该可以正常工作That is how rails works by default: each application instance handles one request at a time. You could turn on multithreaded mode (
config.threadsafe!
), thin is supposed to work ok with that