How to make a good Sidekiq job?
From the Sidekiq wiki, a Sidekiq job should be idempotent and transactional. How should we implement this?
For example, I am sending notification emails via Mandrill. How can I ensure that the email would not be sent multiple times?
Besides, is it good to wrap the jobs in
ActiveRecord::Base.transaction when creating/updating/deleting database records?
For more database-related things, a transaction is good because it gives you the ability to do multiple changes to the data without them partially being finished.
With APIs it is a bit harder since you cannot roll back the execution of the API request. In this case, you basically want to log something immediately after the API request is finished denoting that this part of the job has been completed.
In the case of sending an email, you will need to make sure that your code after a successful send is very simple. Immediately after sending, you will want to write a record on the user that the email was sent. At this point, if the job died and was retried, you would be able to check if that email was sent and then cancel this job.
I think Chris' advice is sound and would really help prevent duplicate job runs. I'm doing something similar now where I mark the record as an email being sent and in the Sidekiq perform method include a check against this field.
Also, just a protip. With Sidekiq or any other background job gem, less is more. So the less it does the better. Also make sure you're passing simple objects as arguments to your worker methods such as
user.id instead of
@user. Let SideKiq do the heavy lifting on the backend when the job executes instead of passing a loaded object to the worker.