黄瓜测试失败,“流关闭(IOError)”

时间:2014-12-04 23:36:29

标签: ruby-on-rails ruby cucumber ioerror

我们目前正在将我们的Rails应用程序升级到Rails 4.在3.2中,我们的Cucumber(1.3.17)测试运行正常(如果可悲的是缓慢),与Capybara(2.4.4),Poltergeist(1.5.1)和PhantomJS (1.9.8)引擎盖下。

但是在4.0.12和4.1.8中,我们在运行中的随机点得到stream closed (IOError)

stream closed (IOError)
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/formatter/pretty.rb:156:in `write'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/formatter/pretty.rb:156:in `puts'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/formatter/pretty.rb:156:in `step_name'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:181:in `block in send_to_all'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:179:in `each'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:179:in `send_to_all'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:173:in `broadcast'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:119:in `visit_step_name'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:112:in `block in visit_step_result'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:170:in `broadcast'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:111:in `visit_step_result'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/step_invocation.rb:43:in `visit_step_result'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/step_invocation.rb:39:in `accept'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:106:in `block in visit_step'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:170:in `broadcast'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:105:in `visit_step'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/step_collection.rb:19:in `block in accept'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/step_collection.rb:18:in `each'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/step_collection.rb:18:in `accept'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:100:in `block in visit_steps'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:170:in `broadcast'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:99:in `visit_steps'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:15:in `block in execute'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/runtime.rb:83:in `block (2 levels) in with_hooks'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/runtime.rb:99:in `before_and_after'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/runtime.rb:82:in `block in with_hooks'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/runtime/support_code.rb:120:in `call'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/runtime/support_code.rb:120:in `block (3 levels) in around'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/language_support/language_methods.rb:9:in `block in around'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/language_support/language_methods.rb:97:in `call'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/language_support/language_methods.rb:97:in `execute_around'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/language_support/language_methods.rb:8:in `around'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/runtime/support_code.rb:119:in `block (2 levels) in around'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/runtime/support_code.rb:123:in `call'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/runtime/support_code.rb:123:in `around'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/runtime.rb:94:in `around'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/runtime.rb:81:in `with_hooks'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:13:in `execute'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/scenario.rb:32:in `block in accept'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/scenario.rb:79:in `with_visitor'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/scenario.rb:31:in `accept'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:58:in `block in visit_feature_element'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:170:in `broadcast'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:57:in `visit_feature_element'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/feature.rb:38:in `block in accept'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/feature.rb:37:in `each'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/feature.rb:37:in `accept'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:27:in `block in visit_feature'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:170:in `broadcast'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:26:in `visit_feature'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/features.rb:28:in `block in accept'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/features.rb:17:in `each'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/features.rb:17:in `each'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/features.rb:27:in `accept'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:21:in `block in visit_features'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:170:in `broadcast'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/ast/tree_walker.rb:20:in `visit_features'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/runtime.rb:49:in `run!'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/lib/cucumber/cli/main.rb:47:in `execute!'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/gems/cucumber-1.3.17/bin/cucumber:13:in `'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/bin/cucumber:23:in `load'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/bin/cucumber:23:in `'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/bin/ruby_executable_hooks:15:in `eval'
/var/lib/jenkins/.rvm/gems/ruby-2.1.5@tallama-integration/bin/ruby_executable_hooks:15:in `'

此错误not the sameclosed stream错误,表示您在关闭后尝试触摸流。

不,rb_thread_fd_close中唯一一次stream closed (IOError)投放在所有MRI中。该代码反过来仅在rb_io_close中调用 - 也就是在关闭文件描述符时;它遍历其他活动线程并查看其中是否有任何一个正在等待关闭的文件描述符。如果有人在等待,则会在等待线程中引发stream closed错误。这巧妙地解释了为什么堆栈跟踪指向黄瓜:这是等待从格式化程序写到STDOUT的线程。但我们没有关于谁关闭文件描述符的任何信息。

因为我知道我在这里处理线程,所以我开始suspect timeout正在杀死一些不应该的东西,但是我无法知道timeout是什么造成混乱;我删除了代码中的那个,但后来在我们正在使用的各种宝石中找到了35个,问题仍然存在。

我们还怀疑,在某些时候,由于内存不足导致其中一个幻像进程被杀死,我们在puts当前进程中添加了一些工具'在每个场景之前的记忆...... IOError s消失了,几乎可以肯定是因为时间问题。当我删除了检测时,错误就会恢复。

我也试图更新到树顶黄瓜和水豚,但似乎没有任何区别。

是否有一些聪明的方法来追踪我尚未尝试过的?你有没有看到这个问题并且知道我需要改进的单线配置改变?你有一个方便的补丁,可以从所有Ruby中删除timeout吗?

2 个答案:

答案 0 :(得分:1)

尝试的想法......

  • 尝试使用Capybara + WebKit缩小问题范围;恶作剧者不是线程安全的(AFAIK)。

  • 通过查看是否为机架超时来缩小问题:

    # config/initializers/timeout.rb
    Rack::Timeout.timeout = 600 
    Rack::Timeout.wait_timeout = 600 # or 0 means never timeout
    
  • 暂时关闭任何调用外部的测试,例如system,sidekiq,eventmachine,延迟作业等。

  • 您想要一个能够从所有Ruby中删除超时的补丁:

    require 'timeout'
    Thread.handle_interrupt(TimeoutError => :never) {
      timeout(10){
        # TimeoutError doesn't occur here
        Thread.handle_interrupt(TimeoutError => :on_blocking) {
          # possible to be killed by TimeoutError
          # while blocking operation
        }
        # TimeoutError doesn't occur here
      }
    }
    

    请参阅Guarding from Timeout Error

  • 在所需的任何断点处跟踪打开的文件对象:

    # List all open File objects.
    ObjectSpace.each_object(File) do |f|
      puts "%s: %d" % [f.path, f.fileno] unless f.closed?
    end
    
    # List the "dangling" File object which we didn't store in a variable.
    ObjectSpace.each_object(File) do |f|
      unless f.closed?  
        printf "%s: %d\n", f.path, f.fileno unless f === filehandle
      end
    end
    

    请参阅Where does Ruby keep track of its open file descriptors

答案 1 :(得分:0)

试试这个:

在打开文件进行阅读后的代码中,您必须将其关闭。   See this similar issue