"""Reserves and commits funds.""" import db # Not actually defined class ErrorCodes(object): FAILED_TO_START = 1 PREPARE_FAILED = 2 INVALID_ACCT_ID = 3 STATUS_UPDATE_FAILED = 4 INVALID_TX_ID = 5 _ERROR_CODE_TO_MESSAGE = { 1 : 'Failed to record start of transaction' # ... Etc } class LedgerException(Exception): """A transaction error.""" def __init__(self, error_code, tx_id=None): super(LedgerException, self).__init__(_ERROR_CODE_TO_MESSAGE[error_code]) self.error_code = error_code self.tx_id = tx_id # Note to reader - this got a special class because it needed more state. # An alternative might be an optional dict on LedgerException for context. class InsufficientFunds(Exception): def __init__(self, tx_id, acct_id, expected_balance, actual_balance): message = ('TX {}: insuffient funds for acct {} (expected:{}, had:{})' .format(tx_id, acct_id, expected_balance, actual_balance)) super(InsufficientFunds, self).__init__(message) self.tx_id = tx_id self.acct_id = acct_id self.expected_balance = expected_balance self.actual_balance = actual_balance class Ledger(object): def __init__(self): pass def Commit(self, ledger_tx_id): """Actually updates the balances in all the accounts. Raises: LedgerException: invalid transaction id or db error. """ pass # Stub def Prepare(self, *reservations): """Reserves the funds from each account. Amounts must sum to zero. Args: *reservations: [acct_id1, amount1], [acct_id2, amount2], ... Returns: A ledger transaction ID. Raises: LedgerException """ assert 0 == sum(reservation[1] for reservation in reservations) try: tx_id = self._Record(reservations) except db.DatabaseException: raise LedgerException(ErrorCode.FAILED_TO_START) try: self._AtomicCheckAndDeduct(reservations, tx_id) except InsufficientFunds as e: # TODO - catch the db failure here and convert it to ledger. self._UpdateStatus(tx_id, 'InsufficientFunds') raise e except db.DatabaseException: # Let layers above this decide whether to retry. self._UpdateStatus(tx_id, 'DbFailed') raise LedgerException(ErrorCode.PREPARE_FAILED, tx_id) try: self._UpdateStatus(tx_id, 'Prepared') except db.DatabaseException: raise LedgerException(ErrorCode.STATUS_UPDATE_FAILED, tx_id) return tx_id def _AtomicCheckAndDeduct(self, reservations, tx_id): """Reserve the funds. Raises: InsufficientFunds: if any account has insufficient funds. LedgerException: if an invalid account id was provided. """ pass # Stub def _Record(self, reservations): """Record the transaction to a database and return an ID.""" return 'fake_ledger_tx_id' def _UpdateStatus(self, tx_id, new_status): pass # Stub
Run
Reset
Share
Import
Link
Embed
Language▼
English
中文
Python Fiddle
Python Cloud IDE
Follow @python_fiddle
Browser Version Not Supported
Due to Python Fiddle's reliance on advanced JavaScript techniques, older browsers might have problems running it correctly. Please download the latest version of your favourite browser.
Chrome 10+
Firefox 4+
Safari 5+
IE 10+
Let me try anyway!
url:
Go
Python Snippet
Stackoverflow Question