Skip to content

Instantly share code, notes, and snippets.

@mrflip
Created May 3, 2011 06:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrflip/952914 to your computer and use it in GitHub Desktop.
Save mrflip/952914 to your computer and use it in GitHub Desktop.
a way to make an asynchronous request in the middleware, and only proceed with the response when both the endpoint and our middleware's responses have completed.
class Barrier < EM::Synchrony::Multi
attr_accessor :env, :status, :headers, :body
def initialize env
super()
@env = env
@acb = env['async.callback']
env['async.callback'] = self
callback do
@acb.call(post_process)
end
end
def pre_process
end
def call shb
status, headers, body = shb
return shb if status == Goliath::Connection::AsyncResponse.first
@status, @headers, @body = status, headers, body
succeed if finished?
end
def post_process
end
def finished?
super && @status
end
end
class AsyncAroundware
def initialize app, barrier_klass
@app = app
@barrier_klass = barrier_klass
end
def call(env, *args, &block)
barrier = @barrier_klass.new(env)
barrier.pre_process
barrier.call(@app.call(env))
end
end
#!/usr/bin/env ruby
$: << File.dirname(__FILE__)+'/../../lib'
require 'goliath'
require 'em-synchrony/em-http'
require 'yajl/json_gem'
require 'async_aroundware.rb'
#
# Here's a way to make an asynchronous request in the middleware, and only
# proceed with the response when both the endpoint and our middleware's
# responses have completed.
#
# To run this, start the 'sleepy.rb' server on port 9002:
#
# ./sleepy.rb -sv -p 9002
#
# And then start the async_aroundware_demo_multi.rb server on port 9000:
#
# ./async_aroundware_demo_multi.rb -sv -p 9000
#
# Now curl the async_aroundware_demo_multi:
#
# $ time curl 'http://127.0.0.1:9000/?delay_1=1.0&delay_2=1.5'
# {"results":{"sleep_2":[1304405129.793657,1.5,1.5003128051757812],"sleep_1":[1304405129.793349,1.0,1.000417947769165]},"errors":{}}
#
BASE_URL = 'http://localhost:9002/'
class MyBarrier < Barrier
def pre_process
add :sleep_1, EM::HttpRequest.new("#{BASE_URL}?delay=#{env.params['delay_1']}").aget
end
def post_process
results = { :results => { :sleep_2 => body }, :errors => {} }
responses[:callback].each{|name, resp| results[:results][name] = JSON.parse(resp.response) }
responses[:errback ].each{|name, err| results[:errors][name] = err.error }
[status, headers, JSON.generate(results)]
end
end
class AsyncAroundwareDemoMulti < Goliath::API
use Goliath::Rack::Params
use Goliath::Rack::Validation::NumericRange, {:key => 'delay_1', :default => 1.0, :max => 5.0, :min => 0.0, :as => Float}
use Goliath::Rack::Validation::NumericRange, {:key => 'delay_2', :default => 0.5, :max => 5.0, :min => 0.0, :as => Float}
#
use AsyncAroundware, MyBarrier
def response(env)
resp = EM::HttpRequest.new("#{BASE_URL}?delay=#{env.params['delay_2']}").get
[200, { }, JSON.parse(resp.response)]
end
end
#!/usr/bin/env ruby
require 'goliath'
# Wait the amount of time given by the 'delay' parameter before responding (default 2.5, max 15.0).
class Sleepy < Goliath::API
use Goliath::Rack::Params
use Goliath::Rack::Validation::NumericRange, {:key => 'delay', :default => 2.5, :max => 15.0, :min => 0.0, :as => Float}
def response(env)
EM::Synchrony.sleep(env.params['delay'])
[ 200,
{ 'X-Sleepy-Delay' => env.params['delay'].to_s },
[ env[:start_time], env.params['delay'], (Time.now.to_f - env[:start_time].to_f) ].inspect
]
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment