如何在Rails中进行异步HTTP请求

9
在我的Rails应用中,我需要向第三方服务发出HTTP请求,由于HTTP请求是同步的,有时需要超过20秒才能从它们那里得到响应。我只是将一些数据推送到该服务,不关心响应内容,因此希望将请求变为异步,这样我的代码会继续执行而不被阻塞。
在ruby中,我该怎么做呢?

3
你应该查看ActiveJobsSidekiq - davegson
我不想使用队列解决方案,因为我认为对于一个简单的HTTP请求来说这有些过度了。使用EventMachine的延迟是否是一个好的解决方案? - fuyi
2个回答

6
我需要发出一个HTTP请求...这样我的代码才会继续执行,而不被阻塞。
def some_action
  Thread.new do
    uri = URI('http://localhost:4567/do_stuff')
    Net::HTTP.post_form(uri, 'x' => '1', 'y' => '2')
  end

  puts "****Execution continues here--before the response is received."
end

这是一个Sinatra应用程序,你可以用来测试它:
1)$ gem install sinatra 2)
#my_sinatra_app.rb

require 'sinatra'

post '/do_stuff' do
  puts "received: #{params}" #Check the sinatra server window for the output.
  sleep 20  #Do some time consuming task.

  puts "Sending response..."
  "The result was: 30"   #The response(which the rails app ignores).
end

output:

$ ruby my_sinatra_app.rb
== Sinatra (v1.4.6) has taken the stage on 4567 for development with backup from Thin
Thin web server (v1.6.4 codename Gob Bluth)
Maximum connections set to 1024
Listening on localhost:4567, CTRL+C to stop

received: {"x"=>"1", "y"=>"2"}
<20 second delay>
Sending response...

127.0.0.1 - - [11/Nov/2015:12:54:53 -0400] "POST /do_stuff HTTP/1.1" 200 18 20.0032

当您导航到Rails应用程序中的some_action()时,Rails服务器窗口将立即输出****执行在此处 - 在收到响应之前。,而Sinatra服务器窗口将立即输出包含在POST请求中发送的数据的params哈希。然后,在20秒延迟后,Sinatra服务器窗口将输出发送响应...

谢谢您的回答,但似乎存在一个问题,因为HTTP请求在新线程中执行,而客户端立即终止,导致Sinatra应用程序无法接收请求。如果我在客户端代码的末尾添加一行 sleep 10 ,那么它就可以工作了,您有什么解决方法吗? - fuyi
@xiaopang,如果你写了t = Thread.new...,并在客户端结尾加上t.join,那么客户端将等待线程执行完毕后才退出。你可以添加一个超时时间(秒):t.join(500) - 7stud
是的,它可以这样工作,但它错过了非阻塞的全部意义,对吧?:) - fuyi
@xiaopang,我改了我的评论。它完全没有理解非阻塞的重点,对吧? 是的...如果在t.join之前有任何代码,那么该代码将在收到响应之前执行,但是如果您的操作中没有其他代码,则视图直到收到响应后才会呈现。 :( - 7stud
@xiaopang,客户端立即终止-你能解释一下你是怎么做到的吗?你的客户端是什么?据我所知,Sinatra应用程序的客户端是你的Rails应用程序。 - 7stud

4

嗨@harshit,你能详细解释一下吗?我尝试了Event Machine,但根据这个文档,代码执行仍然是阻塞的。 - fuyi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接