Sidekiq 在工人中找不到对象

Sidekiq not finding object in worker

当我在我的应用程序中创建一个新的 User 时,我 运行 一个 after_create 方法然后异步触发 Sidekiq worker。

这位工人...

def perform user_id
    @user = ::User.find user_id
    # ...
end

...总是returns以下错误:

ActiveRecord::RecordNotFound: Couldn't find User with 'id'=315928979197048617

但使用 rails 控制台检查用户 ID 是否可找到:

User.find(315928979197048617)
=> #<User id: 315928979197048617>

出现这种情况是因为创建新用户需要一些时间,而工作人员在完成时已经执行了该方法吗?如果,我将如何解决该行为?

您完全正确,Active Record 中的 after_create 挂钩实际上在记录完全提交到数据库之前 运行s。这会导致您的工作脚本和数据库出现竞争条件,其结果是工作人员出现 ActiveRecord::RecordNotFound 错误(尽管如果数据库赢得比赛,那么一切似乎都按计划进行)。

为确保您的用户在您的工作人员尝试访问它之前已保存到数据库中,您应该使用 after_commit 回调。由于您只是在创建时执行此操作,因此您需要 after_commit on: :create.

这确实会导致最后一个问题,after_commit 回调似乎从未 运行 在测试中。这是因为 Rails 将测试包装在事务中,而测试事务从未实际提交,因此不会触发回调。 This blog post has a good write up on using after_commit and recommends the test_after_commit gem 来解决这个问题。