Skip to content

Instantly share code, notes, and snippets.

@drtoast
Last active December 14, 2015 22:19
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drtoast/5157332 to your computer and use it in GitHub Desktop.
Save drtoast/5157332 to your computer and use it in GitHub Desktop.
Using Faraday and Typhoeus to post parallel JSON requests to an API endpoint, and asynchronously handling the responses using custom middleware.
require 'sinatra'
require 'json'
post '/example' do
sleep 5
if request.accept?('application/json')
content_type :json
data = JSON.parse request.body.read
data[:status] = 'OK'
data.to_json
end
end
require 'typhoeus/adapters/faraday'
class PosterResponseHandler < Faraday::Response::Middleware
def call(env)
# "env" contains the request
@app.call(env).on_complete do
# "env" contains the request AND response
response = {
request_url: env[:url].to_s,
response_status: env[:response].status,
response_body: env[:response].body
}
p "PosterResponseHandler: #{response}"
end
end
end
"queued: {:a=>1}"
"queued: {:b=>2}"
"queued: {:c=>3}"
"PosterResponseHandler: {:request_url=>\"http://0.0.0.0:4567/example\", :response_status=>200, :response_body=>\"{\\\"a\\\":1,\\\"status\\\":\\\"OK\\\"}\"}"
"PosterResponseHandler: {:request_url=>\"http://0.0.0.0:4567/example\", :response_status=>200, :response_body=>\"{\\\"c\\\":3,\\\"status\\\":\\\"OK\\\"}\"}"
"PosterResponseHandler: {:request_url=>\"http://0.0.0.0:4567/example\", :response_status=>200, :response_body=>\"{\\\"b\\\":2,\\\"status\\\":\\\"OK\\\"}\"}"
"complete"
require 'typhoeus'
require 'faraday'
require 'json'
require_relative 'handler'
class Poster
def initialize
manager = Typhoeus::Hydra.new(max_concurrency: 100)
@connection = Faraday.new(parallel_manager: manager) do |builder|
builder.use PosterResponseHandler
builder.adapter :typhoeus
end
end
def post_all(data)
@connection.in_parallel do
data.each do |d|
post(d)
# enqueues request and returns immediately
p "queued: #{d}"
end
end
# returns when all requests are complete
p "complete"
end
private
def post(data)
@connection.post do |req|
req.url 'http://0.0.0.0:4567/example'
req.options[:timeout] = 60
req.headers['Content-Type'] = 'application/json'
req.body = data.to_json
end
end
end
Poster.new.post_all [{a: 1}, {b: 2}, {c: 3}]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment