You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails/Sidekiq中存在记录却报ActiveRecord::RecordNotFound错误

问题:Sidekiq执行Job时找不到已存在的Quote记录

报错信息

09:26:23 sidekiq.1 | 2024-07-02T13:26:22.990Z pid=45032 tid=17cw WARN: ActiveRecord::RecordNotFound: Couldn't find Quote with 'id'=1758

核心代码

class CreateOrUpdateApiJob < ApplicationJob
  queue_as :default

  # Called with quote=1758 and action=create
  def perform(quote, action)
     Quote.find(quote)
     if action == "create"
          ApiService.create()
     elsif action === "update"
          ApiService.update()
     end
  end
end

# 任务调用方式
CreateOrUpdateApiJob.perform_later(quote, "create")

环境信息

  • MacBook Pro 2015(2.8GHz四核Intel Core i7、16GB 1600MHz DDR3、1TB SSD、AMD Radeon R9 M370X 2GB),系统macOS Monterey 12.7.5
  • Ruby 3.1.4(rbenv安装)
  • PostgreSQL v15
  • Gems:Rails 6.1.7.4、Sidekiq 7.1.2、ActiveRecord 6.1.7.4、redis 4.8.1、redis-client 0.15.0、pg 1.5.4

启动命令(foreman)

bundle exec rails server -p 3000 -e production
redis-server # 生产环境省略,使用独立Redis
bundle exec sidekiq -c 2 -q default -q mailers

已尝试的方法

  • 传递完整记录
  • 将记录转为字符串解析
  • 重新安装Redis

排查与解决方案

1. 检查数据库环境一致性

Sidekiq默认使用development环境,而你的Rails服务器启动时指定了-e production,这会导致两者连接不同的数据库,出现“本地有记录但Sidekiq查不到”的情况。

解决:启动Sidekiq时显式指定生产环境:

bundle exec sidekiq -c 2 -q default -q mailers -e production

可以在Job中添加日志验证数据库配置,确保和Rails服务器一致:

def perform(quote, action)
  Rails.logger.info "Sidekiq DB config: #{ActiveRecord::Base.connection_config}"
  # ... 原有代码
end

2. 避免事务未提交导致的查询问题

如果调用perform_later时,Quote记录还在未提交的事务中,Sidekiq会在记录写入数据库前执行Job,自然找不到数据。

解决:使用after_commit回调触发Job,确保记录已持久化到数据库:

# app/models/quote.rb
class Quote < ApplicationRecord
  after_commit :trigger_api_job, on: :create

  private

  def trigger_api_job
    CreateOrUpdateApiJob.perform_later(self.id, "create")
  end
end

3. 验证参数类型与实际值

虽然注释说明传入的是1758,但实际参数可能是字符串或其他异常类型,导致find方法匹配失败。

解决:在Job中添加参数日志,并强制转换为整数:

def perform(quote, action)
  Rails.logger.info "Received quote param: #{quote.inspect}, type: #{quote.class}"
  quote_id = quote.to_i
  quote_record = Quote.find_by_id(quote_id)

  if quote_record.nil?
    Rails.logger.error "Quote with id #{quote_id} not found. Existing IDs: #{Quote.pluck(:id).inspect}"
    return
  end

  # ... 原有逻辑
end

4. 检查是否有进程删除了记录

确认是否有其他后台任务、定时任务或手动操作删除了id=1758的Quote记录。可以通过PostgreSQL的pg_stat_activity查看当前活跃进程,或检查数据库审计日志(若开启)。

5. 验证数据库隔离级别

PostgreSQL默认隔离级别为READ COMMITTED,确保Sidekiq的查询能读取到已提交的记录。结合第2点的after_commit方案即可解决这类隔离级别导致的不可见问题。


内容的提问来源于stack exchange,提问作者Evan Wilson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 14:55:59