我有一个 Rails 应用程序,其中有一个 Rake 任务,它使用 concurrent-ruby gem 提供的多线程函数。
我不时遇到Circular dependency detected while autoloading constant
错误。
在谷歌搜索了一下之后,我发现这与使用线程结合加载 Rails 常量有关。
我偶然发现了以下 GitHub 问题:https ://github.com/ruby-concurrency/concurrent-ruby/issues/585和https://github.com/rails/rails/issues/26847
正如这里所解释的,您需要将从新线程调用的任何代码包装在一个Rails.application.reloader.wrap do
或Rails.application.executor.wrap do
块中,这就是我所做的。但是,这会导致死锁。
然后建议用于ActiveSupport::Dependencies.interlock.permit_concurrent_loads
在主线程上包装另一个阻塞调用。但是,我不确定我应该用这个包装哪个代码。
这是我尝试过的,但这仍然会导致死锁:
@beanstalk = Beaneater.new("#{ENV.fetch("HOST", "host")}:#{ENV.fetch("BEANSTALK_PORT", "11300")}")
tube_name = ENV.fetch("BEANSTALK_QUEUE_NAME", "queue")
pool = Concurrent::FixedThreadPool.new(Concurrent.processor_count * 2)
# Process jobs from tube, the body of this block gets executed on each message received
@beanstalk.jobs.register(tube_name) do |job|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
@logger.info "Received job: #{job.id}"
Concurrent::Future.execute(executor: pool) do
Rails.application.reloader.wrap do
# Stuff that references Rails constants etc
process_beanstalk_message(job.body)
end
end
end
end
@beanstalk.jobs.process!(reserve_timeout: 10)
谁能阐明我应该如何解决这个问题?奇怪的是我在生产中遇到了这个问题,而关于这个主题的其他信息似乎暗示它通常应该只发生在开发中。
在生产中,我使用以下设置:
config.eager_load = true
config.cache_classes = true
.
所有环境的自动加载路径都是 Rails 默认的加上两个特定的文件夹(“models/validators”和“jobs/concerns”)。
eager_load_paths
在我的任何配置中都没有修改或设置,因此必须等于 Rails 的默认值。
我正在使用 Rails 5,所以enable_dependency_loading
应该等于false
生产。