假设您使用交易来处理 Stripe 付款并更新用户实体:
@ndb.transactional
def process_payment(user_key, amount):
user = user_key.get()
user.stripe_payment(amount) # API call to Stripe
user.balance += amount
user.put()
Stripe API 调用可能成功,但put
由于争用而失败。然后,用户将被收取费用,但他的帐户不会反映付款情况。
您可以将 Stripe API 调用从事务中取出,然后再执行事务,但似乎您仍然遇到同样的问题。扣款成功,但交易失败,且用户账户未记入。
这似乎是一个非常常见的场景。如何正确处理这一问题?
为了正确操作,事务功能需要是幂等的。因此,您不能在此类函数内进行条带调用,因为这会使其成为非幂等的。
我会将条带调用分开,并且在 API 成功后,我将调用事务函数来更新用户的帐户余额(在发生争用时可以安全地重试)。
甚至可能创建一个单独的、独立的实体来反映条带 API 调用结果?此类实体should没有争用的空间,因为它只写入一次 - 当条带事务发生时。这将使您能够:
- 保留账户交易历史记录 - 指向这些实体
- 进行一些健全性检查,查找孤立条带交易(如果由于某种原因帐户交易调用即使在重试后仍失败)并对此采取措施。
@thebjorn 的评论很好:多步骤方法可以使该过程非常可靠:
- 更新帐户的事务函数,旨在执行条带事务,这也以事务方式将推送任务排入队列 https://cloud.google.com/appengine/docs/standard/python/taskqueue/push/creating-tasks#enqueuing_tasks_in_cloud_datastore_transactions执行条带 API 调用。仅当事务成功时任务才会入队
- 推送队列任务进行 Stripe API 调用(最终创建 Stripe 交易实体),并在成功后调用交易函数来更新账户余额
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)