2

I would like to know to to pause a Root Fiber in ruby (if possible).

I have this Sinatra app, and I am making async calls to an external API with EventMachine. I don't want to respond to the client until the api responds me.

For example, sleeping the Root Fiber in Sinatra until the EventMachine callback wake it up.

Thanks.

Ron
  • 2,215
  • 3
  • 22
  • 30

1 Answers1

2
get '/some/route/' do
  fib = Fiber.current
  req = EM::SomeNonBlokingLib.request
  req.callback do |response|
    fib.resume(response)
  end
  req.errback do |err|
    fib.resume(err)
  end
  Fiber.yield
end

EDIT

In your case you should spawn a Fiber for each request. So. Firstly create Rack config file and add some magick:

# config.ru
BOOT_PATH = File.expand_path('../http.rb',  __FILE__)
require BOOT_PATH

class FiberSpawn
  def initialize(app)
    @app = app
  end

  def call(env)
    fib = Fiber.new do
      res = @app.call(env)
      env['async.callback'].call(res)
    end
    EM.next_tick{ fib.resume }
    throw :async
  end
end

use FiberSpawn
run Http

Then your http Sinatra application:

# http.rb
require 'sinatra'
require 'fiber'

class Http < Sinatra::Base
  get '/' do
    f = Fiber.current
    EM.add_timer(1) do
      f.resume("Hello World")
    end
    Fiber.yield
  end
end

Now you could run it under thin for example:

> thin start -R config.ru

Then if you will visit locakhost:3000 you'll see your Hello World message

fl00r
  • 82,987
  • 33
  • 217
  • 237
  • This is exactly what I am talking about @fl00r. You cannot yield the root fiber. Getting this error "can't yield from root fiber". – Ron Nov 19 '13 at 13:33
  • Thank you @fl00r, you gave a nice start. But, I have been reading, and I don't quite understand a few things. First of all, this is not the best approach, right? because if you get 1000 request, it will create a 1000 fibers. Anyway, the most important question is: When throwing :async, the fiber waits? or it is free to get a new request? because the second one is the expected behavior, but that is not happening. Thanks. – Ron Nov 21 '13 at 09:18
  • 1) For each request you create new Fiber. After Fiber returns response it will be collected by garbage collector. So for 1000 simultaneous requests there will be 1000 Fibers doing their job. 2) You `throw :async` even before Fiber started. You throw it for application server (thin) so it is free to accept another requests. After throwing async on next_tick you resume your fiber – fl00r Nov 21 '13 at 18:20
  • So if your application doesn't do any blocking job you should be able to accept very many requests. But if you are blocking you will be able to process only one parallel request – fl00r Nov 21 '13 at 18:21