When I run this Sidekiq job, it successfully creates the Foo record. But because Foo's after_commit
raises an error, the entire job fails and ends up in the dead job queue. If I fix the after_commit
error and rerun the job, it will create another Foo record (or will do so on retry 😬), which is NOT desirable.
I expect PerformAndCreateFooJob
to complete successfully after the Foo record is successfully created. The after_commit
logic should not cause the job to fail.
after_commit
considered part of this job?after_commit
code from the job?class PerformAndCreateFooJob
include Sidekiq::Job
sidekiq_options retry: 0
def perform = Foo.create
end
class Foo < ApplicationRecord
after_commit -> () { raise }
end
Why is the
after_commit
considered part of this job?
Because it's part of create
(actually part of save
), which you're calling.
Is there a way to decouple the
after_commit
code from the job?
By using insert
to skip the callbacks as explained in the guides
If no way to decouple, is there a better pattern to employ?
Worth adding... it's best practice to ensure jobs are idempotent. There are many reasons a job can be retried, including your own app logic, but also other system conditions. In normal circumstances, this could be as simple as using a find_by
first (assuming your job queuing logic is unlikely to create many jobs for the same record/data), or maybe needs a unique constraint in the DB and logic to rescue a failure there.