【发布时间】:2020-11-11 22:48:53
【问题描述】:
我正在为 API 用例试验 Rails 6。用户会发布大量请求,这些请求会被 Rails 接收并流式传输到另一个地方。这可能会使用 JRuby 运行,但现在我正在使用 MRI Ruby 进行测试。网络服务器是 Puma(开箱即用的导轨安装)。
有没有办法在上传请求主体时将其读取为流,或者 Rails 是否需要等待整个请求上传才能访问它?
使用这个 Curl 命令:
curl -i -X PUT -T data.bin "http://localhost:3000/welcome/stream"
还有这个简单的控制器:
def stream
puts "The stream was called"
io = request.body
until io.eof?
io.read(1024*1024)
puts "Read 1MB"
end
head 200, content_type: "text/html"
end
似乎整个请求在 rails 访问它之前就暂存在某个地方,因为在我的任何 put 出现在控制台之前有很长的延迟。
搜索了一下,似乎是缓存数据的网络服务器(Puma、Unicorn 等),它只有在收到所有数据后才调用 Rails。
有没有办法在流进来时开始读取它或者避免缓冲它?
是 Rack 还是 Puma 进行缓冲?如果是,它在哪里缓冲数据?
【问题讨论】:
-
介意分享回购吗?
-
找到缓冲的位置:github.com/puma/puma/blob/master/lib/puma/server.rb#L501-L502。您示例中的
io变量的类型为Tempfile。如果请求正文大于 112KB,则首先将正文作为一个整体下载到临时文件中,然后才将其传递给 Rails 控制器。据我了解,以流式方式将文件转储到 Tempfile,不消耗任何 RAM。至于你问题的另一部分——如何避免这种缓冲——我还没有答案。 -
嗯,一种选择是从 puma 猴子修补 MAX_BODY 常量,但它可能会严重破坏事情。
-
在我将 MAX_BODY 更改为更大的常量后,没有任何问题,但它仍在缓冲主体,这次是在内存中。
-
可能相关(虽然帖子很旧):stackoverflow.com/questions/4795205/….
标签: ruby-on-rails ruby rack