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 来解决这个问题。
当我在我的应用程序中创建一个新的 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 来解决这个问题。