Я хотел бы использовать функцию потоковой передачи Синатры, представленную в 1.3, в сочетании с некоторым перенаправлением stdout. По сути, это будет прямая трансляция длительной работы. Я изучил этот вопрос и потоковый пример Синатры в README.
Запуск 1.8.7 на OSX:
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
Таким образом, этот бит кода правильно печатает первые три строки и блокируется, пока method_that_prints_text
выполняется и ничего не печатает в браузере. Мне кажется, что stdout пуст при первом вызове и никогда не выводится в буфер out. Я не совсем уверен, каков будет правильный порядок, и буду признателен за любые предложения.
Я попробовал несколько реализаций EventMachine, упомянутых в вопросе выше, но не смог заставить их работать.
UPDATE
Я попытался сделать что-то немного отличное от того, где я запускал метод в новом потоке, и переопределить STDOUT для этого потока, как описано здесь ...
Вместо Kernel.capture_stdout
выше ...
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
С модулем ThreadOut
, перечисленным в ссылке выше, это, кажется, работает немного лучше. Однако это не поток. Единственный раз, когда что-то печатается в браузере, находится в последней строке out << s.string
. StringIO
не имеет возможности потоковой передачи?