require 'rack/fiber_pool' require 'async-rack' require 'eventmachine' module Rhoconnect module Synchrony def setup_sessions(builder) options = {} if settings.respond_to?(:fiberpool_size) options[:size] = settings.fiberpool_size end options[:rescue_exception] = handle_exception builder.use Rack::FiberPool, options unless test? super end def handle_exception Proc.new do |env, e| if settings.show_exceptions? request = Sinatra::Request.new(env) printer = Sinatra::ShowExceptions.new(proc{ raise e }) s, h, b = printer.call(env) [s, h, b] else [500, {}, ""] end end end end module AsyncHelpers def self.included(klass) (klass.instance_methods & self.instance_methods).each do |method| klass.instance_eval{remove_method method.to_sym} end end def catch_all res = nil begin res = catch(:halt) { yield } rescue ApiException => ae res = [ae.error_code, ae.message] rescue Exception => e log e.message + e.backtrace.join("\n") res = [500, e.message] end res end def execute_api_call(client_call = false) f = Fiber.current operation = proc { self.request.env['REQUEST_THREAD'] = Thread.current if(request.env['RHO_ABORT_PROCESS']) res = [500, 'Request is aborted'] else catch_all do res = yield params, current_user, self if params.has_key? :warning Rhoconnect.log params[:warning] response.headers['Warning'] = params[:warning] end res end end } result = nil callback = proc { |proc_res| result = proc_res; f.resume } EventMachine.defer operation, callback Fiber.yield # we can not throw exceptions across threads # so we analyze it in the main thread after the # request has been processed and if result # has error code - then we throw :halt here if Array === result and Fixnum === result.first throw :halt, result end result end end end