gpt4 book ai didi

ruby-on-rails - Rails 中的多线程 : Circular dependency detected while autoloading constant

转载 作者:数据小太阳 更新时间:2023-10-29 06:39:22 25 4
gpt4 key购买 nike

我有一个 Rails 应用程序,其中有一个 Rake 任务,该任务使用并发 ruby gem 提供的多线程函数。

有时我会遇到 Circular dependency detected while autoloading constant 错误。

在谷歌搜索了一下后,我发现这与结合使用线程和加载 Rails 常量有关。

我偶然发现了以下 GitHub 问题:https://github.com/ruby-concurrency/concurrent-ruby/issues/585https://github.com/rails/rails/issues/26847

如此处所述,您需要将从新线程调用的所有代码包装在 Rails.application.reloader.wrap doRails.application.executor.wrap do block ,这就是我所做的。然而,这会导致死锁。

然后建议使用 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

最佳答案

您可能需要更改 eager_load_paths 以包含引发错误的类或模块的路径。 eager_load_paths 已记录 in the Rails Guides .

您遇到的问题是 Rails is not loading these constants应用程序启动时;当它们被其他代码调用时,它会自动加载它们。在多线程 Rails 应用程序中,两个线程在尝试加载这些常量时可能会出现竞争条件。

告诉 Rails 预先加载这些常量意味着它们将在 Rails 应用程序启动时加载一次。仅仅说 eager_load = true 是不够的;您还必须指定类或模块定义的路径。在 Rails 应用程序配置中,这是 eager_load_paths 下的一个 Array。例如,要预先加载 ActiveJob 类:

config.eager_load_paths += ["#{config.root}/app/jobs"]

或者从 lib/ 加载自定义模块:

config.eager_load_paths += ["#{config.root}/lib/custom_module"]

更改预加载设置会影响 Rails 的行为。例如,在 Rails development 环境中,您可能习惯于运行一次 rails server,每次重新加载其中一个端点时,它都会反射(reflect)对代码的任何更改你做了。这不适用于 config.eager_load = true,因为这些类在启动时加载一次。因此,您通常只会更改 productioneager_load 设置。

更新

您可以从 rails console 检查现有的 eager_load_paths。例如,这些是新 Rails 5 应用程序的默认值。如您所见,它不会加载 app/**/*.rb;它加载 Rails 应该知道的特定路径。

Rails.application.config.eager_load_paths
=> ["/app/assets",
"/app/channels",
"/app/controllers",
"/app/controllers/concerns",
"/app/helpers",
"/app/jobs",
"/app/mailers",
"/app/models",
"/app/models/concerns"]

关于ruby-on-rails - Rails 中的多线程 : Circular dependency detected while autoloading constant,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45181922/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com