Rails / ActiveRecord Pessimistic Lock - Do I need to restart after I get the lock?

I have a transaction model in Rails that represents a financial transaction that will be debited from a credit card.

When creating a transaction status :new. When I try to install the board (which will happen in DelayedJob), I update the status to :pending. Any subsequent calls chargewill be ignored if the status is not :new.

Naive version (not relevant to concurrency):

# Trigger a card to be charged
def charge_transaction
  return unless status == :new

  self.transaction do
    self.delay.settle_credit_card
    self.update_attribute(:status, :pending)
  end
end

# Actually do the charging (in a delayed worker)
def settle_credit_card
   # ... Interact with our payment gateway
end

- load_balanced, , concurrency, (- ). , , ( ) .

( 1)

# Trigger a card to be charged
def charge_transaction

  # Obtain row-lock
  self.with_lock do
    self.reload # Reload once lock is obtained - necessary?

    # Check status after lock/reload
    return unless status == :new

    self.delay.settle_credit_card
    self.update_attribute(:status, :pending)
  end
end

( 2)

# Trigger a card to be charged
def charge_transaction

  # Begin transaction without lock
  self.transaction do
    self.reload(lock: true) # Reload and obtain lock

    # Check status after lock/reload
    return unless status == :new

    self.delay.settle_credit_card
    self.update_attribute(:status, :pending)
  end
end

( ) ? ( , ) Rails ? , ?

!

+5
1

. 1 reload - , .

, with_lock lock!, , 100%:

def lock!(lock = true)
  reload(:lock => lock) if persisted?
  self
end

def with_lock(lock = true)
  transaction do
    lock!(lock)
    yield
  end
end

with_lock :

# Obtain row-lock
with_lock do
  # Check status after lock/reload
  return unless status == :new

  delay.settle_credit_card
  update_attribute(:status, :pending)
end

(: self )

+8

All Articles