DEV Community

José Anchieta
José Anchieta

Posted on

Ruby on Rails Pessimistic Locking

Let's say we have two users and we want to create a money transfer between these users, but we have to make sure that if there is an error in any of the steps, the execution will be canceled and other transactions will only be executed when the current transaction ends, this is also known as Race Condition.

To solve this problem or similar problems, there is a technique in Rails called Pessimistic Lock or Pessimistic Strategy, it provides a row-level locking in SQL like SELECT … FOR UPDATE and others and it uses ActiveRecord Transactions. Let's take a look at this code:

def transfer_money_from_user_to_user(user1, user2)
  # Charge 200 from the user1...
  user1.balance(-=200)
  user1.save! # Callbacks and other things...
  # and pay the user2
  user2.balance(+=200)
  user2.save! # Callbacks and other things...
end
Enter fullscreen mode Exit fullscreen mode

If for some reason, the first transaction (charge from user1) fails, it will not prevent the second one to be executed. We have two ways to prevent this using Rails, lock! and with_lock, let's take a look:

Lock!

Using Transactions and lock! we could do something like:

def transfer_money_from_user_to_user(user1, user2)
  # Initialize an ActiveRecord Transaction
  ActiveRecord::Base.transaction do
    # Lock the users
    user1.lock!
    user2.lock!
    # Charge 200 from the user1...
    user1.balance(-=200)
    user1.save!

    # Pay the user2
    user2.balance(+=200)
    user2.save!
  end
end
Enter fullscreen mode Exit fullscreen mode

With_lock

With_lock simplifies our code and creates a transaction wrapper:

def transfer_money_from_user_to_user(user1, user2)
  user1.with_lock do
    # Charge 200 from the user1...
    user1.balance(-=200)
    user1.save!

    # Pay the user2
    user2.balance(+=200)
    user.save!
  end
end
Enter fullscreen mode Exit fullscreen mode

That's it. Using Pessimistic Locking inside Rails is a good way to prevent these kind of failures. See you!

Top comments (0)