升级Sidekiq至7.x与Rails7后执行perform_later遇ActiveSupport::Duration错误
Sidekiq 7.x 下调用
perform_later 触发 ActiveSupport::Duration 错误问题 问题背景
- 升级栈:从 Rails 5.2 + Ruby 2.6 升级至 Rails 7.0.4.2 + Ruby 2.7.7
- 故障现象:调用任意
perform_later都会抛出 ActiveSupport::Duration 相关错误 - 环境对比:Rails 7.x + Ruby 2.7 + Sidekiq 6.x 可正常运行,仅升级到 Sidekiq 7.0.6 时出现故障,推测为 API 变更导致,但未定位具体原因
- 依赖版本:Redis 5.0.6
排查与解决方向
1. 核对 Sidekiq 7.x 延迟任务参数处理逻辑
Sidekiq 7.x 对 ActiveJob perform_later 的参数序列化规则有调整,尤其是针对 ActiveSupport::Duration 的处理。避免直接传递 Duration 对象作为任务参数,或在设置延迟时使用不兼容的写法:
- 错误示例:
SomeJob.perform_later(1.hour)(将 Duration 作为任务参数) - 正确写法:若需设置延迟,使用
set(wait: 1.hour).perform_later(...);若需传递时间参数,转为数值(如1.hour.to_i)或字符串(如1.hour.to_s)后再传递。
2. 验证序列化兼容性
在 Rails 控制台中测试 Rails 和 Sidekiq 对 Duration 的序列化结果是否一致:
# 测试 Rails JSON 序列化 ActiveSupport::JSON.encode(1.hour) # 测试 Sidekiq 序列化 Sidekiq.dump_json(1.hour)
若两者输出格式不同,可在 config/initializers/sidekiq.rb 中配置统一的序列化方式,或手动对 Duration 进行转换后再传入任务。
3. 检查 Job 定义的参数解析
确认所有 Sidekiq Job 的 perform 方法参数是否能正确处理序列化后的数值/字符串。Sidekiq 7 严格限制了可序列化参数类型,若 Job 直接依赖 Duration 对象,需改为接收数值后再转换为 Duration:
# 调整前 def perform(duration) # 使用 duration(Duration 对象) end # 调整后 def perform(seconds) duration = ActiveSupport::Duration.build(seconds) # 使用 duration end
4. 查阅 Sidekiq 7 升级日志
重点关注 Sidekiq 7.0.x 版本中关于 ActiveJob 集成、参数序列化的 breaking change,尤其是与 Rails 7 兼容性相关的条目,可能存在未被注意到的行为变更。
内容的提问来源于stack exchange,提问作者Ferdy
相关产品推荐
相关产品推荐

