How to make async http request in rails
Solution 1
You need to use Event Machine and Fibers in ruby.
Solution 2
I need to make a http request...so my code will continue execution and not been blocked.
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
Here's a sinatra app you can use to test it:
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
When you navigate to some_action()
in your rails app, the rails server window will immediately output ****Execution continues here--before the response is received.
, and the sinatra server window will immediately output the params
hash, which contains the data sent in the post request. Then after a 20 second delay the sinatra server window will output Sending response...
.
fuyi
Experience:Android application development, Web application development. Enterprise system modeling, System architect, Team leading, Project management. Interested areas: IT product manager, technical leading, application architecture, data mining, machine learning Fight hard to create scalable, maintainable and testable software
Updated on July 26, 2022Comments
-
fuyi almost 2 years
In my rails app, I need to make a http request to 3rd party service, since http request is synchronous, sometimes it takes more than 20 seconds to get response back from them.
I just push some data to that service, I don't care about what the response will be, so I want to make the request asynchronous, so my code will continue execution and not been blocked.
How could I do it in ruby?
-
fuyi over 8 yearsthanks for the answer, but seems like there is a problem, since the http request is executed in a new thread, and the client terminated immediately, the sinatra app never receive the request. If I add a line at the end of the client code
sleep 10
, then it works, any idea how to remedy this? -
7stud over 8 years@xiaopang, If you write
t = Thread.new...
, and then at the end of the client you addt.join
then the client won't exit until after the Thread finishes executing. You can add a timeout in seconds:t.join(500)
. -
fuyi over 8 yearsYep, it works this way, but it missed the whole point of none blocking, right? : )
-
7stud over 8 years@xiaopang, I changed my comment. it missed the whole point of none blocking, right? Yeah...any code before the
t.join
will execute before the response is received, but if there's no other code in your action, the view isn't going to render until after the response is received. :( -
fuyi over 8 yearsHi @harshit, can you elaborate a bit ? I tried Event Machine, but according to this doc, the code execution is still blocking
-
7stud over 8 years@xiaopang, the client terminated immediately--Can you explain how you are doing that? What is your client? As far as I can tell, the client of the Sinatra app is your Rails app.