thoughtbot / capybara-webkit

A Capybara driver for headless WebKit to test JavaScript web apps
https://thoughtbot.com/open-source
MIT License
1.97k stars 427 forks source link

Handle IO::EAGAINWaitReadable error #946

Closed taylorzr closed 8 years ago

taylorzr commented 8 years ago

This isn't a bug I can reproduce, but it has happened intermittently on our CI server while running feature tests. The error we were getting was:

execution expired
...
[unimportant stacktrace]
...
------------------
--- Caused by: ---
IO::EAGAINWaitReadable:
  Resource temporarily unavailable - read would block
  ./spec/support/acceptance/site_prism/avantcredit/en-US/application/apply_contract_page.rb:160:in `wait_for_contract'

I researched this error, IO::EAGAINWaitReadable, but there isn't much documentation. I did find a stackoverflow page which led me to believe one of our gems wasn't handling this error.

We're using a million gems of course, but the gems primarily used in our feature tests are rspec, capybara-webkit, capybara, and siteprism. So I searched the source of each gem looking for references to IO::EAGAINWaitReadable or IO::WaitReadable, and this line in capybara-webkit was the only one I found.

So hypothesis: This error occurs while our feature test is waiting for an element to no longer exist. This waiting uses siteprism's _waituntilinvisible method, which in turn utilizes capybara's _hasselector? method. While waiting, this IO::EAGAINWaitReadable error occurs in a separate thread in capybara-webkit. As you can see rspec reports the cause of the failure, but the stack trace of the cause is lacking. I'm assuming this lacking stacktrace is normal, and is hiding the real cause of the failure.

I've run this on our test suite more than 10 times with this patch, and I haven't seen any failures that we were previously seeing. So I believe this will patch will properly fix these errors.

Please let me know if you need any other information. Thanks.

taylorzr commented 8 years ago

Or I could be way off, it seems like rescuing IO::WaitReadable should also rescue IO::EAGAINWaitReadable.

begin
  raise IO::EAGAINWaitReadable
rescue IO::WaitReadable
  puts 'rescued'
end
# rescued
# => nil
tmertens commented 8 years ago

The exception in question was being raised by a Timeout block in site_prism, which in turn revealed a minor defect in core ruby, where the cause of the Timeout error was being incorrectly assigned: https://bugs.ruby-lang.org/issues/12741