升级至Rails 7.1.5后写入操作指向错误分片问题求助
核心问题
从Rails 6.1.7升级到7.1.5后,显式指定分片的connected_to代码块内,写入操作未指向目标分片,反而固定指向某一个分片(调换connects_to内的分片顺序会改变错误目标),但连接查询能正确返回目标分片名称。
可能原因及排查方向
1. 模型继承与connected_to调用对象不匹配
分片配置定义在抽象类ServeRecord上,但代码中使用MyModel.connected_to。如果MyModel未继承ServeRecord,这个块的作用域仅覆盖MyModel,而继承自ServeRecord的User模型会使用默认分片连接,导致写入错误。
2. Database.yml配置格式错误
你的database.yml存在缩进问题,分片配置未正确嵌套在production环境下。错误的缩进会导致Rails无法正确识别分片连接配置,进而使用默认的错误连接。
3. Rails 7+分片默认逻辑变更
Rails 7对分片连接的默认行为做了调整:当未显式指定默认分片时,可能会取connects_to定义中的最后一个分片作为默认(而非Rails 6中的第一个),这会导致未正确切换时写入错误分片。
4. Rails 7.1.5特定bug
部分用户反馈Rails 7.1.5中存在抽象类分片切换的bug,导致connected_to块内的写入操作未正确切换连接。
解决方案
步骤1:修正Database.yml格式
确保所有配置项正确缩进在production下:
production: primary: adapter: postgresql database: dashboard username: user password: password shard_one: writing: adapter: postgresql database: serve username: user password: password shard_two: writing: adapter: postgresql database: serve username: user password: password
步骤2:确保connected_to调用对象正确
在分片的抽象类ServeRecord上调用connected_to,确保作用域覆盖所有继承它的模型:
ServeRecord.connected_to(role: :writing, shard: :shard_one) do puts "Current DB: #{ServeRecord.connection.current_database}" User.create!(name: "Test User") end
步骤3:显式指定默认分片
在ServeRecord中添加默认分片配置,避免Rails自动选择错误的默认连接:
class ServeRecord < ActiveRecord::Base self.abstract_class = true self.default_shard = :shard_one # 按需设置默认分片 connects_to shards: { shard_one: { writing: :shard_one, reading: :shard_one }, shard_two: { writing: :shard_two, reading: :shard_two } } end
步骤4:验证Rails版本问题
尝试升级到Rails 7.1的最新补丁版本(如7.1.6),或临时回退到7.1.4,确认是否为7.1.5的特定bug。如果是版本问题,可以等待官方修复或使用临时补丁。
步骤5:检查模型继承关系
确认User和MyModel都正确继承自ServeRecord:
class User < ServeRecord # ... end class MyModel < ServeRecord # ... end
内容的提问来源于stack exchange,提问作者Adarsh Shrivastav

