使用AJAX请求在Cucumber中自动加载相关的竞争条件

时间:2014-07-22 22:11:23

标签: ruby-on-rails thread-safety cucumber capybara capybara-webkit

我正在使用Cucumber和capybara-webkit进行我的应用程序在Ruby 2.0.0,Rails 4.1上的集成测试。在我的黄瓜测试套件中进行了一些测试,意外地开始吐出这样的错误:

  Circular dependency detected while autoloading constant UiValidators::ParameterFinder (RuntimeError)
  /Users/kingp/.rvm/gems/ruby-2.0.0-p451@triquest/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:484:in `load_missing_constant'
  /Users/kingp/.rvm/gems/ruby-2.0.0-p451@triquest/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:180:in `const_missing'
  /Users/kingp/Projects/rails-triquest/app/controllers/contacts_controller.rb:2:in `<class:ContactsController>'
  /Users/kingp/Projects/rails-triquest/app/controllers/contacts_controller.rb:1:in `<top (required)>'
  /Users/kingp/.rvm/gems/ruby-2.0.0-p451@triquest/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:247:in `require'
  ...

错误显示'循环依赖',但实际上它是在Rails自动加载器尝试加载已经在其加载常量集中的常量时抛出的。通常这确实是由于循环依赖,但我很确定在我的应用程序中并非如此。分支与崩溃测试和我分支的稳定分支之间的差异表明,唯一的变化是coffeescript文件,视图模板,迁移和我正在编写的新黄瓜功能。我没有触及任何控制器或型号代码。

我最终在rails自动加载器中插入了一些日志代码,以帮助我弄清楚发生了什么:

  # Inserted at activesupport-4.1.1/lib/active_support/dependencies.rb:467
  _thread_id_for_debug = Thread.current.object_id
  STDERR.puts "*** #{loaded.count} #{from_mod} #{const_name} - #{_thread_id_for_debug}"

loaded是自动加载代码文件的一组路径,from_mod请求来自的上下文,const_name我们尝试加载的常量。在撞车事故发生之前,所有这些最终让我得到了这个:

  *** 104 Object SitesController - 70180261360940
  *** 105 Object ContactsController - 70180240113760
  *** 105 SitesController UiValidators - 70180261360940
  *** 105 Object UiValidators - 70180261360940
  *** 105 UiValidators ParameterFinder - 70180261360940
  *** 107 UiValidators ParameterFinder - 70180240113760 

看起来两个线程正试图自动加载相同的常量。我的猜测是,在第一个线程完成加载之前,常量的名称被添加到Rails的'加载'常量集中。第二个线程无法解析常量(因为负载尚未完成),要求自动加载器找到它,并且当自动加载器在其“加载”集中看到常量时引发自动加载器。

在测试的这一点上,两个控制器(SitesController和ContactsController)正在响应几乎同时启动的AJAX请求。

我找到了解决崩溃的方法,只需在AJAX之前包含对模块UiValidators::ParameterFinder的引用。但这似乎很脆弱,也不是很优雅。如果没有打开测试环境的急切加载,还有其他方法可以避免这个问题吗?

2 个答案:

答案 0 :(得分:0)

我遇到了同样的问题(没有Cucumber,只有Capybara&amp; Poltergeist)。设置config.eager_load = true甚至不能为我工作(不太明白为什么不......)。

我最终使用Spring并且自那以来没有出现循环依赖性错误。

答案 1 :(得分:0)

使用Sidekiq时,我在Rails 4.1.4中遇到了同样的问题。我假设在调用 active_support 中的const_missing时,线程Sidekiq工作人员内部的竞争条件导致了各种各样的障碍。

除了确保我当前的环境会执行急切加载,即通过config.eager_load = true我还必须将我的工作人员正在使用的所有组件从lib目录添加到config.eager_load_paths(通过config.eager_load_paths += %W(#{config.root}/lib)内的config/application.rb

这是必要的,因为我假设设置config.eager_load = true只会让Rails急切加载app/目录的内容。

App::Application.config.eager_load_paths
=> [
  [0] "/home/archive/releases/20140721180504/app/assets",
  [1] "/home/archive/releases/20140721180504/app/controllers",
  [2] "/home/archive/releases/20140721180504/app/helpers",
  [3] "/home/archive/releases/20140721180504/app/mailers",
  [4] "/home/archive/releases/20140721180504/app/models",
  [5] "/home/archive/releases/20140721180504/app/services",
  [6] "/home/archive/releases/20140721180504/app/workers"
]

两者的结合似乎有助于解决这个问题。