2011-12-23 18 views
0

1.3で導入されたSinatraのストリーミング機能を、標準出力リダイレクトと組み合わせて使用​​したいと思います。これは、基本的に長時間実行されるジョブのライブストリーミング出力になります。私はthis questionとREADMEのSinatraストリーミングサンプルを調べました。 OSX上で1.8.7を実行Sinatra 1.3ストリーミング(Ruby標準出力リダイレクト)

require 'stringio' 
require 'sinatra' 

$stdout.sync = true 

module Kernel 
    def capture_stdout 
    out = StringIO.new 
    $stdout = out 
    yield out 
    ensure 
    $stdout = STDOUT 
    end 
end 

get '/' do 
    stream do |out| 
    out << "Part one of a three part series... <br>\n" 
    sleep 1 
    out << "...part two... <br>\n" 
    sleep 1 
    out << "...and now the conclusion...\n" 

    Kernel.capture_stdout do |stream| 
     Thread.new do 
      until (line = stream.gets).nil? do 
       out << line 
      end 
     end 
     method_that_prints_text 
    end 
    end 
end 

def method_that_prints_text 
    puts "starting long running job..." 
    sleep 3 
    puts "almost there..." 
    sleep 3 
    puts "work complete!" 
end 

だから、コードのこのビットが適切に最初の3つの文字列を出力し、ブロックmethod_that_prints_text実行しながら、ブラウザには何も印刷されません。最初の呼び出しではstdoutが空であり、出力バッファには出力されません。私は、適切な注文がどんなものであろうと確信しておらず、何か提案を感謝するでしょう。

上記の質問に記載されているEventMachine実装のいくつかを試しましたが、動作させることができませんでした。

UPDATE

私は新しいスレッドでメソッドを実行していたところへ、わずかに別の何かを試みたが、hereを説明するように、そのスレッドのためのSTDOUTを上書き...

の代わりに上記Kernel.capture_stdout

..上記のリンクに記載されている ThreadOutモジュール付き。

s = StringIO.new 

Thread.start do 
    Thread.current[:stdout] = s 
    method_that_prints_text 
end.join 

while line = s.gets do 
    out << line 
end 

out << s.string 

、これは少し良く動作しているようです。しかしそれは流れません。何かがブラウザに印刷される唯一の時間は、最終行out << s.stringです。 StringIOにはストリーム機能がありませんか?

答えて

1

私は、s.stringが時間の経過とともに定期的に更新されていることを発見することによってこの問題を解決しました。そのため、別のスレッドで出力をキャプチャして差分を取得し、ストリームアウトしました。文字列リダイレクトは通常のIOオブジェクトのようには動作しないように見えます。

s = StringIO.new 
t = Thread.start do 
    Thread.current[:stdout] = s 
    method_that_prints_text 
    sleep 2 
end 

displayed_text = '' 
while t.alive? do 
    current_text = s.string 
    unless (current_text.eql?(displayed_text)) 
    new_text = current_text[displayed_text.length..current_text.length] 
    out << new_text 
    displayed_text = current_text * 1 
    end 
    sleep 2 
end 
関連する問題