[英]In GAE, how to make money transfer transaction idempotent?
GAE 文档警告:
尽可能使您的数据存储事务具有幂等性,这样如果您重复一个事务,最终结果将是相同的。
假设我想在两个人之间转账一笔钱:
class User(ndb.Model):
balance = ndb.IntegerProperty(default=0)
@ndb.transactional(xg=True)
def transfer(from_key, to_key, amount)
from = from_key.get()
to = to_key.get()
from.balance -= amount
to.balance += amount
ndb.put_multi([from, to])
由于这不是幂等的,它可能会发生不止一次并导致问题。 我想重构它以确保事务是幂等的。
这个答案提出了一个解决方案:
要解决此问题,您可以通过创建“交易密钥”并将该密钥作为交易的一部分记录在新实体中来使交易具有幂等性。 第二个事务可以检查该事务密钥,如果找到,则不执行任何操作。 一旦您对交易完成感到满意,或者您放弃重试,就可以删除交易密钥。
但我不明白如何实现它。
有人可以解释如何使此交易幂等吗?
您可以根据交易详情创建一个密钥,例如:
import datetime
import hashlib
>>> txn = {
'from_account': '100123',
'to_account': '200456',
'amount': 123456,
'timestamp': datetime.datetime(2017, 9, 23, 10, 11, 12, 123456)
}
# Combine the values into a string
>>> raw_key = u''.join([unicode(v) for k, v in sorted(txn.items())])
>>> print raw_key
1234561001232017-09-23 10:11:12.123456200456
# hash the key so exposing it in logs etc. doesn't expose transaction data
>>> key = hashlib.sha256().hexdigest()
>>> print key
261c516faa580d6604850967c5804f3fce5f323aae90e36debdb84aa0b950dcb
您可以将散列键存储在数据存储中,或者使其成为您的事务模型的计算属性(如果有),并在尝试创建新事务之前对其进行查询。
class TransactionKeys(ndb.model):
pass
class TransactionHandler(webapp2.RequestHandler):
def post(self):
txn = {
'from_account': self.request.POST['from'],
'to_account': self.request.POST['to'],
'value': self.request.POST['value']
'timestamp': datetime.datetime.now()
}
raw_key = u''.join([unicode(v) for k, v in sorted(txn.items())])
txn_key = hashlib.sha256().hexdigest()
...
transfer(from_key, to_key, amount, txn_key)
@ndb.transactional(xg=True)
def transfer(from_key, to_key, amount, txn_key)
already_exists = TransactionKeys.get_by_id(txn_key)
if already_exists:
raise DuplicateTransactionError('Duplicate transaction!')
else:
transaction_key = TransactionKey(id=txn_key)
from = from_key.get()
to = to_key.get()
from.balance -= amount
to.balance += amount
ndb.put_multi([from, to, txn_key])
这种方法并不完美——例如,如果两个相同的事务在同一微秒内到达,它就会失败。 您可以添加其他数据以使密钥更加独特,例如 App Engine 实例 ID 或请求 ID。
最后,强制性免责声明:我不是安全专业人士,如果你用真钱做这件事,你应该进行适当程度的尽职调查,并考虑专业赔偿/公共责任保险。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.