Skip to content

Instantly share code, notes, and snippets.

@furkanmustafa
Last active February 10, 2016 03:38
Show Gist options
  • Save furkanmustafa/2d9edefcaa0336ed982b to your computer and use it in GitHub Desktop.
Save furkanmustafa/2d9edefcaa0336ed982b to your computer and use it in GitHub Desktop.
Sample Asynchronous action code for rails
# FROM: http://www.jonb.org/2013/01/25/async-rails.html @jbaudanza
# Modified to get it working.
module AsyncController
# This is the rack endpoint that will be invoked asyncronously. It will be
# wrapped in all the middleware that a normal Rails endpoint would have.
class RackEndpoint
attr_accessor :action
def call(env)
@action.call(env)
end
end
module ClassMethods
def prepareAsyncMiddleware!
@endpoint = RackEndpoint.new
# LocalCache isn't able to be instantiated twice, so it must be removed
# from the new middleware stack.
middlewares = Rails.application.middleware.middlewares.reject do |m|
reject = false
reject = true if m.klass.name == "ActiveSupport::Cache::Strategy::LocalCache"
reject
end
@wrapped_endpoint = middlewares.reverse.inject(@endpoint) do |a, e|
e.build(a)
end
end
def asyncMiddleware=(newM)
@wrapped_endpoint = newM
end
def asyncMiddleware
@wrapped_endpoint
end
def asyncActionEndpoint
@endpoint
end
def asyncActionEndpoint=(newAE)
@endpoint = newAE
end
end
def self.included(mod)
mod.extend(ClassMethods)
mod.prepareAsyncMiddleware!
end
# Called to finish an asynchronous request. Can be invoked with a block
# or with the symbol of an action name.
def finish_request(action_name=nil, &proc)
async_callback = request.env.delete('async.callback')
env = request.env.clone
if !action_name
env['async_controller.proc'] = proc
action_name = :_async_action
end
self.class.asyncActionEndpoint.action = self.class.action(action_name)
begin
async_callback.call(self.class.asyncMiddleware.call(env))
rescue Exception => e
# TODO: Should return a crash response
puts "CRASHED!".white.on_red
puts e.inspect
end
end
def _async_action
instance_eval(&request.env['async_controller.proc'])
end
def async!
render :text => "", :status => -1
end
end
# FROM: http://www.jonb.org/2013/01/25/async-rails.html @jbaudanza
# Modified to get it working.
class TestController < ActionController::Base
include AsyncController
def bulkdata
_since = DateTime.strptime(params[:from], '%s')
_until = DateTime.strptime(params[:to], '%s')
Thread.new do
sleep 30
finish_request do
render text: "This response has responded 30 seconds later, but the server doesn't get blocked."
end
end
async!
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment