views:

74

answers:

1

If your response in Sinatra returns an 'eachable' object, Sinatra's event loop will 'each' your result and yield the results in a streaming fashion as the HTTP response. However, if there are concurrent requests to Sinatra, it will iterate through all the elements of one response before handling another request. If we have a cursor to the results of some DB query, that means we have to wait for all the data to be available before handling a concurrent query.

I've looked at the async-sinatra gem and http://macournoyer.com/blog/2009/06/04/pusher-and-async-with-thin/, thinking these would solve my problem, but I've tried out this example:

require 'sinatra/async'

class AsyncTest < Sinatra::Base
  register Sinatra::Async

  aget '/' do
    body "hello async"
  end

  aget '/delay/:n' do |n|
    EM.add_timer(n.to_i) { body { "delayed for #{n} seconds" } }
  end
end

and the /delay/5 request doesn't work concurrently as I expect it to, i.e. I make 3 requests concurrently and Chrome's debugger notes the response times as roughly 5, 10, and 15 seconds.

Am I missing some setup or is there another way to tell Sinatra/Thin to handle requests in a concurrent manner?

Update: Here's another wrench in this (or possibly clears things up): Running curl -i http://localhost:3000/delay/5 concurrently has the correct behavior (2 requests each come back in ~5 seconds). Running ab -c 10 -n 50 http://locahost:3000/delay/5 (the Apache benchmark utility) also returns something reasonable for the total time (~25 seconds). Firefox exhibits the same behavior as Chrome. What are the browsers doing different from the command-line utilities?

A: 

When you are about to handle the response of the object do this:

fork do
  handle request...
  exit 99
end

and if you don't need to do not wait for this child process to end.. with a:

child = fork do
  handle request...
  exit 99
end

Process.detach(child)

It's a simple way to handle multiple requests, however I am not sure what ORM you may be using for those DB queries, but you could get into table/row level locking problems with multiple processes trying to hit the db, if that is what you mean when you say handling requests...

Nick
The problem isn't asynchronously handling the DB requests, it's asynchronously returning the Sinatra responses to the client. I know that EventMachine will allow you to `defer` a `proc` and have a callback `proc` to execute when the deferred code is complete. The DB in question is MongoDB, by the way, and we have a cursor to the returned results. The problem is to tell Sinatra to iterate over cursors concurrently and generate responses from independent cursors concurrently.
Kenny Peng