基本上,我有以下问题。有一个处理付款的订单处理系统。在非常罕见的情况下,我们最终得到双重订单,因为当我们通过API查询信用卡处理程序时,如果用户真的很快刷新页面,信用卡处理器有时会将这两个请求作为“成功“我们在系统中获得两个成功的”付费“活动。
所以我的想法是实现对付款内容(每个订单)的锁定,如果锁被锁定,请告诉客户(如果客户很快刷新页面会发生这种情况 - 我认为在我们的情况下它是实际上是有意的)。
所以我想和Redis一起做这件事并想出来:
def _PaymentInterlock(object):
def __init__(self, pp):
self.key = GlobalKey('pay_ilk_%s'%pp._ident)
def lock(self):
self.key(1)
def unlock(self):
self.key.delete()
def try_lock(self):
result = self.key()
if result == 1:
return False
self.lock()
return True
唯一的问题是 try_lock 操作不是原子操作(而不是真正的比较和存储操作),所以从技术上讲,两个WSGI工作者可以得到一个密钥未命中,然后锁定“锁定”导致同样的问题。
关于如何解决这类问题的任何建议吗?
答案 0 :(得分:1)
由于其单线程特性,在Redis中锁定实际上非常容易。只需使用SetNX即可。该链接页面上有更多信息,但基本思路是:
这是此设计模式的简化/修改版本。我在制作中使用了非常相似的东西:
def getRedisLock(name, max_time, r):
lock = r.setnx(name, int(time.mktime(time.gmtime())))
if not lock:
lock_time = int(r.get(name))
#if the lock expired (assume some client failed)
if lock_time + max_time < int(time.mktime(time.gmtime())):
old_time = int(r.getset(name, int(time.mktime(time.gmtime()))))
if old_time == lock_time:
lock = True
#If you still have no lock, do something special here, if you want
if not lock:
pass
return lock
def releaseRedisLock(self, name):
r = self.r
return r.delete(name)
在每次交易之前,只需使用一些唯一的transaction_id调用getRedisLock()。如果您获得锁定,则只处理信用卡,否则告诉用户不要成为混蛋:)