使用Thin和Sinatra异步迭代请求的响应

时间:2010-10-15 20:09:18

标签: ruby concurrency sinatra thin eventmachine

如果你在Sinatra中的回复返回一个'eachable'对象,那么Sinatra的事件循环将“每个”你的结果并以流式方式产生结果作为HTTP响应。但是,如果有对Sinatra的并发请求,它将在处理另一个请求之前迭代一个响应的所有元素。如果我们对某些数据库查询的结果有一个游标,那意味着我们必须等待所有数据在处理并发查询之前可用。

我看过async-sinatra gem和http://macournoyer.com/blog/2009/06/04/pusher-and-async-with-thin/,认为这些可以解决我的问题,但我已经尝试过这个例子:

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

并且/delay/5请求并不像我期望的那样同时工作,即我同时发出3个请求,Chrome的调试器将响应时间记录为大约5,10和15秒。

我是否错过了某些设置,还是有其他方式告诉Sinatra / Thin以并发方式处理请求?

更新:这是另一个扳手(或可能清除): 同时运行curl -i http://localhost:3000/delay/5具有正确的行为(每个请求在约5秒内返回2个请求)。运行ab -c 10 -n 50 http://locahost:3000/delay/5(Apache基准实用程序)也会在总时间(~25秒)内返回合理的值。 Firefox表现出与Chrome相同的行为。什么是与命令行实用程序不同的浏览器?

2 个答案:

答案 0 :(得分:4)

所以最后,我发现该示例确实有效,我最终可以让Sinatra同时流式传输每个结果,主要是使用Pusher和Async页面中的EM.defer想法。卷曲和Apache基准测试证实这是有效的。

它在浏览器中不起作用的原因是浏览器限制了到同一URL的连接数。我知道并发连接到单个域(也是一个低数字)的限制,但不是(似乎)所有与单个URI的连接都被序列化:

http://maillist.caucho.com/pipermail/resin-interest/2009-August/003998.html

我不知道这是否可配置,我只在Firefox中看到域范围的配置,但这就是问题。

答案 1 :(得分:-1)

当您要处理对象的响应时,请执行以下操作:

fork do
  handle request...
  exit 99
end

如果您不需要等待此子进程结束..使用:

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

Process.detach(child)

这是一种处理多个请求的简单方法,但是我不确定您可能正在使用哪些ORM来进行这些数据库查询,但是如果有多个进程尝试访问数据库,您可能会遇到表/行级别锁定问题是你说处理请求时的意思......