我有一个相当复杂的问题,导致我的数据库中出现重复记录。
我在 nginx 1.0.5 上运行 uwsgi(4 个工作人员)和 Django 1.4.5。问题是一些客户端对同一路径发出重复请求,如下面的 nginx 日志所示:
10.205.132.51 - - [26/Aug/2013:16:59:41 -0300] "GET /path/to/ HTTP/1.1" 499 0 "http://mydomain.com.br/path/" "Mozilla/5.0 (Windows NT 6.1; rv:21.0) Gecko/20100101 Firefox/21.0"
10.205.132.51 - - [26/Aug/2013:16:59:41 -0300] "GET /path/to/ HTTP/1.1" 200 7372 "http://mydomain.com.br/path/" "Mozilla/5.0 (Windows NT 6.1; rv:21.0) Gecko/20100101 Firefox/21.0"
这些请求正在同时处理,在下面这个视图的情况下,我进入了一个竞争条件,两者都get_or_create
没有找到结果并且都创建了一个新对象:
with transaction.commit_on_success():
f, created = cls.objects.get_or_create(
key1=value1,
key2=value2,
defaults={...})
在你问之前,不,这两个键不是unique_together
数据库中。
两个请求都200
从 Django 返回状态码,但是 nginx 丢弃了一个,导致409
状态码(冲突)。这transaction.commit_on_success()
部分是减少的尝试,但没有解决问题。
我还尝试了一个基于缓存的锁,使用这个函数:
@contextmanager
def cache_exclusive(name, timeout=10):
""" found at http://coffeeonthekeyboard.com/simple-out-of-process-lock-with-python-and-memcached-2-985/ """
key = 'cache_lock:%s' % name
lock = cache.add(key, True, timeout=timeout) # Fails if key already exists.
yield lock # Tell the inner block if it acquired the lock.
if lock: # Only clear the lock if we had it.
cache.delete(key)
以及具有此用法的唯一名称:
with cache_exclusive('key1 and key2') as granted:
if not granted:
return
# do the get_or_create stuff...
但这也没有解决。您对如何处理这些重复请求有什么建议吗?