-
-
Notifications
You must be signed in to change notification settings - Fork 942
Description
IO#read_nonblock blocks sometimes for SSL Sockets. Based on Aaron Patterson's monkey patch in http://gist.github.com/251244, I added some logging in Thread.current[] for debugging and monkey patched Net::BufferedIO#rbuf_fill to be:
def rbuf_fill
Thread.current[:rbuf_fill_loops] = 0
begin
Thread.current[:rbuf_fill_loops] += 1
Thread.current[:rbuf_fill_stage] = "pre read_nonblock #{Time.now}"
@rbuf << @io.read_nonblock(BUFSIZE)
rescue OpenSSL::SSL::SSLErrorReadable, Errno::EWOULDBLOCK, Errno::EAGAIN => e
Thread.current[:rbuf_fill_stage] = "rescue"
raise if e.is_a?(OpenSSL::SSL::SSLErrorReadable) && e.message != "read would block"
Thread.current[:rbuf_fill_error] = "#{$!.class}: #{$!.message}"
Thread.current[:rbuf_fill_stage] = "pre io select"
retry if IO.select [@io], nil, nil, 30.0
raise Timeout::Error, e.message
end
Thread.current[:rbuf_fill_stage] = nil
Thread.current[:rbuf_fill_loops] = nil
Thread.current[:rbuf_fill_error] = nil
@rbuf
end
Usually it works great (I use Net::HTTP to scrape some sites, which in turn uses this method), but every now and then it hangs at the read_nonblock for SSL sockets. If you wrap the whole method in a Timeout::timeout set for 5 minutes or so, you can see that it rarely but occasionally goes off and that when you examine Thread.current[:rbuf_fill_stage] it reads "pre read_nonblock ..." with a timestamp approx 5 minutes before the timeout fired. Also, for the 10 or so cases I've observed so far, Thread.current[:rbuf_fill_loops] is always 2, and Thread.current[:rbuf_fill_error] is always "OpenSSL::SSL::SSLErrorReadable: read would block".
I'm using JRuby 1.7.3 in ruby 1.9 mode, I know there are later JRuby releases but none seem to have any patches related to read_nonblock so I figure this is still a bug even in those releases.