vadviktor
12/30/2012 - 5:01 PM

How to use deferred objects in thin-powered Sinatra app (without using async_sinatra)

How to use deferred objects in thin-powered Sinatra app (without using async_sinatra)

require 'rubygems'
require './app.rb'

run App
require 'logger'
require 'sinatra'
require 'rack/fiber_pool'

require 'em-synchrony'
require 'em-http-request'
require 'em-synchrony/em-http'

$error_Handler = lambda {|env, exception| [503,{}, "fiber error handler #{exception}"] }


class DeferrableResponse

  def initialize  deferrable
    @callback = proc { |*args| args }
    @errback = proc { |*args| args }
    @deferrable = deferrable
  end

  def callback &block
    @callback = block
  end

  def errback &block
    @errback = block
  end


  def respond
    current_fiber = Fiber.current
    @deferrable.callback { |*args| current_fiber.resume @callback.call(*args) }
    @deferrable.errback { |*args| current_fiber.resume @errback.call(*args) }
    Fiber.yield
  end

end

class App < Sinatra::Base

  enable :logging

  use Rack::FiberPool, size: 10, rescue_exception: $error_Handler

  before do
    logger.info env['REQUEST_URI']
  end

  get '/em' do #  regular even machine stuff, shouldn't block
    logger.info "ello"

    conn = EM::HttpRequest.new('http://coffeesounds.com')
    response = DeferrableResponse.new conn.aget

    response.callback do|a|
      logger.info "Success!"
      status 201
      body "em callback: #{a.response.length}"
    end

    response.errback do |a|
      logger.error "CB error #{err}"
      status 510
      body "FAIL FAIL"
    end

    response.respond
  end

  get '/ems' do
    # this is already using monkey patched EM::HTTP
    r = EM::HttpRequest.new('http://coffeesounds.com').get
    status 201
    body  "Body: #{r.response.length}"
  end
end

Rack fiber pool + EM deferrables + em-synchrony is a nice idea.

While em-synchrony powered libraries work out of the box, objects which are deferrables don't play that nicely.

Lets use fibers then (just like em-synchrony, but with less transparency)!

GEM
  remote: http://rubygems.org/
  specs:
    addressable (2.3.2)
    coderay (1.0.8)
    cookiejar (0.3.0)
    daemons (1.1.9)
    em-http-request (1.0.3)
      addressable (>= 2.2.3)
      cookiejar
      em-socksify
      eventmachine (>= 1.0.0.beta.4)
      http_parser.rb (>= 0.5.3)
    em-socksify (0.2.1)
      eventmachine (>= 1.0.0.beta.4)
    em-synchrony (1.0.2)
      eventmachine (>= 1.0.0.beta.1)
    eventmachine (1.0.0)
    http_parser.rb (0.5.3)
    method_source (0.8.1)
    pry (0.9.10)
      coderay (~> 1.0.5)
      method_source (~> 0.8)
      slop (~> 3.3.1)
    rack (1.4.1)
    rack-fiber_pool (0.9.2)
    rack-protection (1.3.2)
      rack
    sinatra (1.3.3)
      rack (~> 1.3, >= 1.3.6)
      rack-protection (~> 1.2)
      tilt (~> 1.3, >= 1.3.3)
    slop (3.3.3)
    thin (1.5.0)
      daemons (>= 1.0.9)
      eventmachine (>= 0.12.6)
      rack (>= 1.0.0)
    tilt (1.3.3)

PLATFORMS
  ruby

DEPENDENCIES
  em-http-request
  em-synchrony
  pry
  rack-fiber_pool
  sinatra
  thin
source :rubygems

gem 'sinatra'
gem 'rack-fiber_pool'
gem 'thin'
gem 'em-synchrony'
gem 'em-http-request'
gem 'pry', require: 'pry'