title: How to avoid race condition in a rails model that records payments and running balance?
body: <p>I have a simple model, <code>Payments</code>, which has two fields <code>amount</code> and <code>running_balance</code>. When a new <code>payment</code> record is created, we look for the <code>running_balance</code> of its previous payment, say <code>last_running_balance</code> and save <code>last_running_balance+amount</code> as the <code>running_balance</code> of the current payment.</p>
  
  <p>Here are our three failed attempts to implement the <code>Payments</code> model. For simplicity, assume the previous payment always exists and <code>id</code>s are increasing as payments are created.</p>
  
  <p>Attempt 1:</p>
  
  <pre><code>class Payments &lt; ActiveRecord::Base
      before_validation :calculate_running_balance
      private
      def calculate_running_balance
          p = Payment.last
          self.running_balance = p.running_balance + amount
      end
  end
  </code></pre>
  
  <p>Attempt 2:</p>
  
  <pre><code>class Payments &lt; ActiveRecord::Base
      after_create :calculate_running_balance
      private
      def calculate_running_balance
          p = Payment.where("id &lt; ?", id).last
          update!(running_balance: p.running_balance + amount)
      end
  end
  </code></pre>
  
  <p>Attemp 3:</p>
  
  <pre><code>class Payments &lt; ActiveRecord::Base
      after_commit :calculate_running_balance
      private
      def calculate_running_balance
          p = Payment.where("id &lt; ?", id).last
          update!(running_balance: p.running_balance + amount)
      end
  end
  </code></pre>
  
  <p>These implementations may cause race conditions in the system as we are using <code>sidekiq</code> to create payments in the background. Suppose the last payment is <code>payment 1</code>. When two new payments, say <code>payment 2</code> and <code>payment 3</code> are created at the same time, their <code>running_balance</code> might be computed based on the running balance of <code>payment 1</code> because it might be the case that when <code>payment 3</code> is figuring out its running balance <code>payment 2</code> has not been saved to the database yet.</p>
  
  <p>In particular, I am interested in a fix that avoids the running condition. I am also keen on looking at other rails apps that implement similar payment systems.</p>