Module: DoubleEntry::Locking
- Includes:
- Configurable
- Defined in:
- lib/double_entry/locking.rb
Overview
Lock financial accounts to ensure consistency.
In order to ensure financial transactions always keep track of balances consistently, database-level locking is needed. This module takes care of it.
See DoubleEntry.lock_accounts and DoubleEntry.transfer for the public interface to this stuff.
Locking is done on DoubleEntry::AccountBalance records. If an AccountBalance record for an account doesn't exist when you try to lock it, the locking code will create one.
script/jack_hammer can be used to run concurrency tests on double_entry to validates that locking works properly.
Defined Under Namespace
Classes: Configuration, Lock, LockDisaster, LockMustBeOutermostTransaction, LockNotHeld, LockWaitTimeout
Class Method Summary collapse
-
.balance_for_locked_account(account) ⇒ Object
Return the account balance record for the given account name if there's a lock on it, or raise a LockNotHeld if there isn't.
-
.lock_accounts(*accounts) ⇒ Object
Run the passed in block in a transaction with the given accounts locked for update.
Methods included from Configurable
Class Method Details
.balance_for_locked_account(account) ⇒ Object
Return the account balance record for the given account name if there's a lock on it, or raise a LockNotHeld if there isn't.
55 56 57 |
# File 'lib/double_entry/locking.rb', line 55 def self.balance_for_locked_account(account) Lock.new([account]).balance_for(account) end |
.lock_accounts(*accounts) ⇒ Object
Run the passed in block in a transaction with the given accounts locked for update.
The transaction must be the outermost transaction to ensure data integrity. A LockMustBeOutermostTransaction will be raised if it isn't.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/double_entry/locking.rb', line 35 def self.lock_accounts(*accounts) lock = Lock.new(accounts) if lock.in_a_locked_transaction? lock.ensure_locked! yield else lock.perform_lock(&Proc.new) end rescue ActiveRecord::StatementInvalid => exception if exception. =~ /lock wait timeout/i raise LockWaitTimeout else raise end end |