我可以通过使用这个retry_on_expired_cache helper 在某些地方解决这个问题:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
class << self
# Retry automatically on ActiveRecord::PreparedStatementCacheExpired.
# (Do not use this for transactions with side-effects unless it is acceptable
# for these side-effects to occasionally happen twice.)
def retry_on_expired_cache(*_args)
retried ||= false
yield
rescue ActiveRecord::PreparedStatementCacheExpired
raise if retried
retried = true
retry
end
end
end
我会这样使用它:
MyModel.retry_on_expired_cache do
@my_model.save
end
不幸的是,这就像玩“打地鼠”一样,因为在我的滚动部署期间,这种崩溃一直在我的应用程序中发生(我无法同时重新启动所有 Rails 进程。)
我终于知道我可以关闭prepared_statements来完全避免这个问题。 (见this other question and answers on StackOverflow。)
我担心性能损失,但我发现很多设置prepared_statements: false的人的报告,他们没有发现任何问题。例如https://news.ycombinator.com/item?id=7264171
我在config/initializers/disable_prepared_statements.rb创建了一个文件:
db_configuration = ActiveRecord::Base.configurations[Rails.env]
db_configuration.merge!('prepared_statements' => false)
ActiveRecord::Base.establish_connection(db_configuration)
这允许我继续从 DATABASE_URL 环境变量设置数据库配置,'prepared_statements' => false 将被注入到配置中。
这完全解决了ActiveRecord::PreparedStatementCacheExpired 错误,让我的服务更容易实现高可用性,同时仍然能够修改数据库。