Database Reference
In-Depth Information
Our account schema also changes just a bit to store the pending transaction IDs along with
each account:
{
_id
:
1
,
balance
:
100
,
txns
:
[] }
{
_id
:
2
,
balance
:
0
,
txns
:
[] }
The top-level transfer function transfers an amount from one account to another as before,
but we have added a maximum amount of time allowable for the transaction to complete. If a
transaction takes longer, it will eventually be rolled back by a periodic process:
def
def
transfer
(
amt
,
source
,
destination
,
max_txn_time
):
txn
=
prepare_transfer
(
amt
,
source
,
destination
)
commit_transfer
(
txn
,
max_txn_time
)
Note that in the preceding code we now have a two-phase commit model of our transfer: first
the accounts are prepared, then the transaction is committed. The code to prepare the transfer
is as follows:
def
def
prepare_transfer
(
amt
,
source
,
destination
):
# Create a transaction object
now
=
datetime
.
utcnow
()
txnid
=
ObjectId
()
txn
=
{
'_id'
:
txnid
,
'state'
:
'new'
,
'ts'
:
datetime
.
utcnow
(),
'amt'
:
amt
,
'src'
:
source
,
'dst'
:
destination
}
db
.
transactions
.
insert
(
txn
)
# "Prepare" the accounts
result
=
db
.
accounts
.
update
(
{
'_id'
:
source
,
'balance'
: {
'$gte'
:
amt
} },
{
'$inc'
: {
'balance'
:
-
amt
},
'$push'
: {
'txns'
:
txn
[
'_id'
] } })
iif
not
not
result
[
'updatedExisting'
]:
db
.
transaction
.
remove
({
'_id'
:
txnid
})
raise
raise
InsufficientFundsError
(
source
)
db
.
accounts
.
update
(
{
'_id'
:
dest
},