Mutex for ActiveRecord Model
ruby, ruby-on-rails-4
Solution
I found a gem Remote lock when searching for a solution for my problem. It is a mutex solution that uses Redis in the backend.
It:
- is accessible for all processes
- does not lock the database
- is in memory -> fast and no IO
The method looks like this now
def nasty
$lock = RemoteLock.new(RemoteLock::Adapters::Redis.new(REDIS))
$lock.synchronize("capi_lock_#{user_id}") do
http_request_1
http_request_2
update_user
end
end
Problem
My User model has a nasty method that should not be called simultaneously for two instances of the same record. I need to execute two http requests in a row and at the same time make sure that any other thread does not execute the same method for the same record at the same time. ``` class User ... def nasty_long_running_method // something nasty will happen if this method is called simultaneously // for two instances of the same record and the later one finishes http_request_1 // before the first one finishes http_request_2. http_request_1 // Takes 1-3 seconds. http_request_2 // Takes 1-3 seconds. update_model end end ``` For example this would break everything: ``` user = User.first Thread.new { user.nasty_long_running_method } Thread.new { user.nasty_long_running_method } ``` But this would be ok and it should be allowed: ``` user1 = User.find(1) user2 = User.find(2) Thread.new { user1.nasty_long_running_method } Thread.new { user2.nasty_long_running_method } ``` What would be the best way to make sure the method is not called simultaneously for two instances of the same record?