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

如果你在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相同的行为。 什么是与命令行实用程序不同的浏览器?

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

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

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

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

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

 fork do handle request... exit 99 end 

如果你不需要等待这个子进程结束..用:

 child = fork do handle request... exit 99 end Process.detach(child) 

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