2016-08-20 67 views
2

我正在嘗試使用Sidekiq來運行以下作業。使用Sidekiq進行活動作業並獲取ActiveJob :: DeserializationError

作業在未排隊(perform_now)時表現良好,但在調用爲(perform_later)時使用Sidekiq失敗。

AddEmployeesToRoomJob.perform_now room ## works fine 
AddEmployeesToRoomJob.perform_later room ## breaks in Sidekiq 

錯誤:

AddEmployeesToRoomJob JID-da24b13f405b1ece1212bbd5 INFO: fail: 0.003  sec 
2016-08-20T14:57:16.645Z 19456 TID-owmym5fbk WARN:  {"class":"ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper","wrapped" :"AddEmployeesToRoomJob","queue":"default","args": [{"job_class":"AddEmployeesToRoomJob","job_id":"0ba5bd30-e281-49a7-a93f- 6e50445183ac","queue_name":"default","priority":null,"arguments": [{"_aj_globalid":"gid://dragonfly/Room/1"}],"locale":"en"}],"retry":true, "jid":"da24b13f405b1ece1212bbd5","created_at":1471704675.739077,"enqueued _at":1471705036.6406531,"error_message":"Error while trying to  deserialize arguments: Couldn't find Room with  'id'=1","error_class":"ActiveJob::DeserializationError","failed_at":14717 04675.946183,"retry_count":4,"retried_at":1471705036.644416} 
2016-08-20T14:57:16.645Z 19456 TID-owmym5fbk WARN:  ActiveJob::DeserializationError: Error while trying to deserialize  arguments: Couldn't find Room with 'id'=1 
2016-08-20T14:57:16.645Z 19456 TID-owmym5fbk WARN:  /Users/tamlyn/.rvm/gems/ruby-2.2.3/gems/activerecord- 5.0.0.1/lib/active_record/relation/finder_methods.rb:357:in  `raise_record_not_found_exception!' 

我的工作 類AddEmployeesToRoomJob < ApplicationJob queue_as:默認

def perform(room) 
    employees = Employee.all 
    if employees.length > 0 
     employees.each do |employee| 
     UserRoom.create(user: employee, room: room) 
     end 
    end 
    end 
end 

我思考 我不明白爲什麼它找不到我進入執行方法的房間。就好像它在排隊/ JSON化工作中失去了那個變量?

的Sidekiq文檔說

「不幸的是,這意味着如果作業排隊後[房間]記錄被刪除,但執行方法被調用之前,異常處理是不同的。」

他們建議的方法,但我看不出這將幫助我:

rescue_from ActiveJob::DeserializationError do |exception| 
    # handle a deleted user record 
end 

在此先感謝您的幫助!

+1

https://github.com/mperham/sidekiq/wiki/Problems-and-Troubleshooting#can not-find-modelname-with-id12345 –

回答

5

我不認爲將Room對象傳遞給Sidekiq worker是個好主意。我總是傳遞一個數據庫對象的主鍵,然後重新查詢。嘗試這個。

AddEmployeesToRoomJob.perform_later room.id 

def perform(room_id) 
    room = Room.find(room_id) 
    employees = Employee.all 
    if employees.length > 0 
     employees.each do |employee| 
     UserRoom.create(user: employee, room: room) 
     end 
    end 
    end 
end 
+0

謝謝!這完美的作品... –

+0

@TamlynR如果這個答案解決了你的問題,你會介意把它作爲答案。如果沒有,請讓我知道還需要什麼。 – kcdragon

0

將Ruby對象作爲參數發送給sidekick worker是不可取的。您可以發送Id作爲參數,並在執行方法內初始化對象。如果想發送對象,那麼你可以將Ruby對象轉儲爲任何其他格式,如Json/Binary/yml,如下所示。

object.to_json 

或者

Marshal.dump(object) 

並採用內部對象之前執行方法,你可以反序列化對象的Ruby對象,如下所示。

JSON.parse(serialized_object) 

或者

Marshal.load(serialized_object) 

這些是你的問題的解決方案,而不是理想的解決方案。

+1

謝謝,這真的很有趣 –

1

如果可以確保此模型已提交,則可以將模型傳遞給作業。在提交當前事務之前排隊作業是一個經典錯誤。

你可以在這裏找到更多的信息: https://github.com/mperham/sidekiq/wiki/FAQ#why-am-i-seeing-a-lot-of-cant-find-modelname-with-id12345-errors-with-sidekiq

在我們的項目中,我們編寫了一個模型,關注能夠添加動態後提交的代碼塊。

module AfterCommitOnce 
    extend ActiveSupport::Concern 

    included do 
    after_commit :execute_after_commit_handlers 
    end 

    def after_commit_once(&block) 
    @after_commits = @after_commits || [] 
    @after_commits << block 
    end 

    private 

    def execute_after_commit_handlers 
    @after_commits = @after_commits || [] 
    @after_commits.each do |ac| 
     ac.call 
    end 
    @after_commits = [] 
    end 
end 

添加這種關注你Employee模式,您可以指定要執行後提交所有更改到你的數據庫與工作:

... 
employee.after_commit_once do 
    AddEmployeesToRoomJob.perform_later 
end 
employee.save! 
相關問題