How to make async http request in rails

10,278

Solution 1

You need to use Event Machine and Fibers in ruby.

Github: em-http-request

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....

Share:
10,278
fuyi
Author by

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, 2022

Comments

  • fuyi
    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
    fuyi over 8 years
    thanks 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
    7stud over 8 years
    @xiaopang, If you write t = Thread.new..., and then at the end of the client you add t.join then the client won't exit until after the Thread finishes executing. You can add a timeout in seconds: t.join(500).
  • fuyi
    fuyi over 8 years
    Yep, it works this way, but it missed the whole point of none blocking, right? : )
  • 7stud
    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
    fuyi over 8 years
    Hi @harshit, can you elaborate a bit ? I tried Event Machine, but according to this doc, the code execution is still blocking
  • 7stud
    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.