在努力从 distribute_reads 转向本机 Rails 6 多数据库支持时,我遇到了一个奇怪的行为,我仍然不确定这是一个错误还是配置问题。
// database.yml
default: &default
adapter: postgresql
encoding: unicode
pool: 10
reaping_frequency: 10
timeout: 5000
username: my_username
password: my_password
database: my_database
schema_search_path: 'public,utils'
development: &development
primary:
<<: *default
database: my_database
host: 'localhost'
primary_replica:
<<: *default
database: my_database
host: 'localhost'
replica: true
third_replica:
<<: *default
database: my_database
host: 'localhost'
replica: true
test: &test
primary:
<<: *default
database: 'my_database_test'
host: 'localhost'
primary_replica:
<<: *default
database: 'my_database_test'
host:'localhost'
replica: true
third_replica:
<<: *default
database: 'my_database_test'
host: 'localhost'
replica: true
我还更改了连接到该代码库所有记录的
ApplicationRecord
# application_record.rb
connects_to shards: {
default: { writing: :primary, reading: :primary_replica },
admin: { writing: :primary, reading: :third_replica }
}
现在当我处于开发阶段时,它的行为完全符合预期
> ActiveRecord::Base.connected_to(role: :reading, shard: :default, prevent_writes: true) do
EventType.count
end
(72.3ms) SELECT COUNT(*) FROM "event_types" /*line:(pry):2:in `block in <main>'*/
=> 2
这是正确的记录数。当我运行测试并使用相同的行时,包装器外部的
EventType.count
也会计算出正确的数字,但是无论我在任何模型中检查什么记录,connected_to
都会导致 0
。
> EventType.count
=> 1
> ActiveRecord::Base.connected_to(role: :reading, shard: :default, prevent_writes: true) do
EventType.count
end
=> 0
开发/测试中的副本实际上是同一个数据库,因此在我的情况下应该不可能获得
0
。
当使用
writing
角色时,它确实有效
> ActiveRecord::Base.connected_to(role: :writing, shard: :default) do
EventType.count
end
=> 1
请注意,
shards:
部分似乎并不重要,因为它也通过database:
打破了简化版本,并且没有third_replica
我是否缺少有关 Rails 功能的某些内容?是否存在与此不兼容的测试相关的内容?我找不到与此相关的任何文档。
最后,问题来自于我们在整个测试设置中的事务
DatabaseCleaner.strategy = :transaction
这证明这是我们代码库中一个更大的问题。当将查询包装到事务中并使用
connected_to
时,您基本上会脱离所述事务,并且在我们的特定情况下会产生很多一致性问题。这纯粹是逻辑上的,但将其添加到堆栈中可能与最初的内容不兼容。
结论是在使用事务和处理只读副本时要小心。
Laurent 你是否能够解决这个问题,因为在 rspec 中,它只发生在事务块中,只有你在 rspec 中为此做了任何解决方法,因为在开发中它工作正常。 预先感谢,我无法发表评论,因为我没有声誉