简体   繁体   English

从流块写入文件

[英]Write to file from stream block

Working on a web service that sometimes needs to return large files, and want it to send something to the client quickly so the client doesn't time out waiting for the start of the data.处理有时需要返回大文件的 Web 服务,并希望它快速向客户端发送某些内容,以便客户端不会因等待数据开始而超时。 stream seemed perfect for this, but I ran into a problem. stream似乎很适合这个,但我遇到了一个问题。

Dumb example:愚蠢的例子:

get '/path' do
  status 200
  headers 'Content-Type' => 'text/plain'
  stream do |out|
    sleep 1
    out << "Hello,\n"
    sleep 1
    out << "World!\n"
  end
end

This works fine:这工作正常:

$  curl http://localhost:4567/path
   Hello,
   World!

But I have a side log that the service writes to, and trying to mix File I/O with the streaming API doesn't work at all:但是我有一个服务写入的侧日志,并且尝试将文件 I/O 与流 API 混合根本不起作用:

get '/path' do
  status 200
  headers 'Content-Type' => 'text/plain'
  File.open '/tmp/side-log', 'a' do |lf|
    stream do |out|
      lf.puts "Woo!"
      sleep 1
      out << "Hello,\n"
      sleep 1
      out << "World!\n"
    end
  end
end

Now I get this:现在我明白了:

$ curl http://localhost:4567/path
curl: (18) transfer closed with outstanding read data remaining

Puma doesn't indicate any problems on the server side, but Thin exits entirely: Puma 没有表示服务器端有任何问题,但 Thin 完全退出:

hello2.rb:13:in `write': closed stream (IOError)
        from hello2.rb:13:in `puts'
        from hello2.rb:13:in `block (3 levels) in <main>'
        from vendor/bundle/gems/sinatra-1.4.6/lib/sinatra/base.rb:437:in `block (2 levels) in stream'
        from vendor/bundle/gems/sinatra-1.4.6/lib/sinatra/base.rb:628:in `with_params'
        from vendor/bundle/gems/sinatra-1.4.6/lib/sinatra/base.rb:437:in `block in stream'
        from vendor/bundle/gems/sinatra-1.4.6/lib/sinatra/base.rb:403:in `call'
        from vendor/bundle/gems/sinatra-1.4.6/lib/sinatra/base.rb:403:in `block in each'
        from vendor/bundle/gems/eventmachine-1.0.8/lib/eventmachine.rb:1062:in `call'
        from vendor/bundle/gems/eventmachine-1.0.8/lib/eventmachine.rb:1062:in `block in spawn_threadpool'
[1]+  Exit 1                  ruby hello2.rb

So what should I do if I want to write something out to someplace other than the output stream from inside the stream block?那么如果我想从流块内部向输出流以外的地方写一些东西,我该怎么办?

Not sure if this is the best solution, but using the asynchronous em-files gem worked for me, even in Puma (which I understand is not EventMachine-based):不确定这是否是最好的解决方案,但使用异步em-files gem 对我有用,即使在 Puma 中也是如此(我理解它不是基于 EventMachine 的):

require 'em-files'  

get '/path' do
  status 200
  headers 'Content-Type' => 'text/plain'
  EM::File.open '/tmp/side-log', 'a' do |lf|
    stream do |out|
      lf.write "Woo!\n"
      sleep 1
      out << "Hello,\n"
      sleep 1
      out << "World!\n"
   end
  end
end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM