Imagine a case where you have a model with callback when 2 requests are send at the same time, and a new record is created in that model with callbacks. Your goal is to trigger the callback 1 time to make sure no race conditions happens.
Lets have an example to go more deeper into that.
We have a courses and students table and each course can have many students. We wanna trigger an email when the specific course got its first student. Here if 2 or more students try to enter the course at the same time we can get several emails but our goal is to be just informed via 1 email.
class Course extend ActiveRecord has_many :students after_create :notify_via_email def notify_via_email if students.count == 1 # send email to the administration end end end
Here we have in general and there is no way to tell whether this is the second student or the first because of race condition.
There is a good solution which makes possible to prevent race conditions using redis or other in memory storage to store, have a sidekiq worker and make it to work as a queue so that one callback can be processed at any given time.
class EmailExecutorJob < ApplicationJob def perform(student) lock_key = "EmailExecutorJob:#{student.id}" if redis.get(lock_key) self.class.set(wait: 1.second).perform_later(student) else redis.set(lock_key, student.id, 1.second) if students.count == 1 # send email to the administration end redis.delete(lock_key) end end end
And in the students model we can have this code
class Course extend ActiveRecord has_many :students after_create :notify_via_email def notify_via_email EmailExecutorJob.perform_later(self) end end
As you can see we converted model callback to trigger EmailExecutorJob which checks whether other job is running and delays the current one. We are storing current student id in redis with prefixed key and that way we clearly can tell whether there is another job for the same name is running or not.
In this way we can prevent any race conditions.
P.S.
I haven't tested this and give just an example, but if you get stuck anywhere feel free to contact and I will be glad to help with such scenarios.