aaronkelton
aaronkelton

Reputation: 409

Why does my Sidekiq job fail from a model's after_commit code?

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.

class PerformAndCreateFooJob
  include Sidekiq::Job
  sidekiq_options retry: 0

  def perform = Foo.create
end
class Foo < ApplicationRecord
  after_commit -> () { raise }
end

dead job queue showing Perform and create foo job failed

Upvotes: 0

Views: 142

Answers (1)

smathy
smathy

Reputation: 27961

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.

Upvotes: 1

Related Questions