JRuby + Poltergeist で並列化すると落ちる問題
CapybaraとPoltergeistを使ってクローリングしたい時、せっかくだから並列化して高速化を図りたい。ところが適当にスレッドを分けて並列化するとRubyが止まってしまう。そしてPhantomjsだけはバックグラウンドで動き続けていると言う謎の挙動があり、二週間くらい悩んでいた。おそらくはJRuby特有の問題で、普通のMRIでは再現しなかった。
どうやらJRuby側でPhantomjsからのコンソール出力をうまく受け取れていないことが問題の根元らしい。とりあえずPoltergeistのclient.rb
にあるstart
とstop
をモンキーパッチしてJRuby側で受け取らないようにしてみた。
module Capybara::Poltergeist
class Client
def start
@pid = Process.spawn(*command.map(&:to_s), pgroup: true)
ObjectSpace.define_finalizer(self, self.class.process_killer(@pid))
end
def stop
if pid
kill_phantomjs
ObjectSpace.undefine_finalizer(self)
end
end
end
end
問題は解決した。
ちなみにstart
のコードはもともとこんな風になっている。
def start
@read_io, @write_io = IO.pipe
@out_thread = Thread.new {
while !@read_io.eof? && data = @read_io.readpartial(1024)
@phantomjs_logger.write(data)
end
}
process_options = {}
process_options[:pgroup] = true unless Capybara::Poltergeist.windows?
redirect_stdout do
@pid = Process.spawn(*command.map(&:to_s), process_options)
ObjectSpace.define_finalizer(self, self.class.process_killer(@pid))
end
end
なんとなく怪しさを感じる。STDOUT redirectionはJRubyと相性よくなさそうだ。