1

當我在我的應用程序中創建一個新的User時,我運行一個after_create方法,然後異步觸發一個Sidekiq工作人員。Sidekiq在工作人員沒有找到對象

這個工人...

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

...總是返回以下錯誤:

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

但是用鋼軌控制檯來檢查,如果用戶ID容易找到:

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

這是否發生是因爲t他創建新用戶需要一些時間,並且工作人員在完成時已經執行了該方法?如果我如何解決這個問題?

回答

3

你是絕對正確的,Active Record中的after_create鉤子實際上在記錄完全提交到數據庫之前運行。這會導致與你的工作者腳本和數據庫的競爭狀況,其結果是工作者中的ActiveRecord::RecordNotFound錯誤(儘管如果數據庫贏得比賽,那麼一切似乎都按計劃進行)。

爲確保您的用戶在工作人員嘗試訪問數據庫之前已保存到數據庫,您應該使用after_commit回調。由於您只是在創建時執行此操作,因此您需要after_commit on: :create

這確實會導致最後一個問題,after_commit回調似乎無法在測試下運行。這是因爲Rails在事務中包裝測試,並且測試事務從未實際提交,所以回調不會觸發。 This blog post has a good write up on using after_commit並建議test_after_commit gem來解決這個問題。