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

Rails ActiveJob无法感知数据库更新问题求助

问题分析与解决方案

从你的控制台日志里的CACHE标记就能一眼看出问题:Rails的查询缓存在ActiveJob的整个执行周期内都生效了,导致循环里的每次查询都直接复用了第一次的缓存结果,根本没去数据库拉取最新的变更。

为什么直接调用ReImport.watch_batch正常?因为在普通请求或控制台里,Rails会在请求结束/命令执行完后自动清理查询缓存;但ActiveJob是一个持续运行的后台任务,查询缓存会一直保留到Job执行结束,所以后续的查询全命中了缓存,看不到数据库的变化。

快速修复方案:禁用查询缓存

你可以用ActiveRecord::Base.uncached块包裹循环内的数据库查询,强制每次都去数据库获取最新数据:

修改ReImport模型的watch_batch方法:

def self.watch_batch(num)
  batch = ReImport.where(batch: num)
  total = batch.count
  remaining = batch.where(completed: false)
  remaining_count = remaining.count
  p "initial remaining: #{remaining_count}"

  while !remaining.empty? do
    p 'wait 10 seconds...'
    sleep(10)
    p '...seconds finished...'

    # 用uncached块包裹所有需要获取最新数据的查询
    ActiveRecord::Base.uncached do
      batch = ReImport.where(batch: num)
      remaining = batch.where(completed: false)
      current_remaining_count = remaining.count
      p "remaining_count: #{remaining_count}"
      p "remaining . count: #{current_remaining_count}"
      p "(remaining_count > current_remaining_count): #{(remaining_count > current_remaining_count)}"

      if remaining_count > current_remaining_count
        p '=== WATCH_BATCH: update found! ==='
        remaining_count = current_remaining_count
        ReImportBatchChannel.broadcast_to("re_import_batch_#{num}", {update: true})
      else
        p '=== WATCH_BATCH: nothing changed yet ==='
      end
    end
  end
  p '=== WATCH_BATCH COMPLETED (or timeout reached) ==='
end

也可以在每次sleep后手动清除查询缓存:

sleep(10)
ActiveRecord::Base.connection.clear_query_cache # 清除缓存
# 然后执行查询

不过uncached块更优雅,它只会在块内禁用缓存,不会影响Job里的其他逻辑。

更优的架构建议:替换轮询为事件触发

这种每隔10秒轮询数据库的方式其实很浪费资源,而且延迟高。更好的做法是在数据变更时主动触发广播,完全不需要后台Job轮询:

在ReImport模型里添加回调,当completed字段变更时自动发送广播:

class ReImport < ApplicationRecord
  # 当completed字段被修改并保存后触发
  after_update :broadcast_batch_update, if: :saved_change_to_completed?

  private

  def broadcast_batch_update
    # 向对应的频道广播更新
    ReImportBatchChannel.broadcast_to("re_import_batch_#{batch}", {update: true})
  end
end

这样只要Project A更新了completed字段,客户端就能立刻收到更新通知,既高效又实时,还省去了维护后台Job的麻烦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:52:21