feat: base 优化safe_get_or_create
This commit is contained in:
parent
9388eada7d
commit
53a56ace1f
|
|
@ -117,25 +117,23 @@ class BaseModel(models.Model):
|
||||||
def safe_get_or_create(cls, defaults=None, **kwargs):
|
def safe_get_or_create(cls, defaults=None, **kwargs):
|
||||||
defaults = defaults or {}
|
defaults = defaults or {}
|
||||||
|
|
||||||
for attempt in range(3):
|
for i in range(3):
|
||||||
try:
|
try:
|
||||||
# 先尝试获取(带锁)
|
obj = cls.objects.create(**kwargs, **defaults)
|
||||||
try:
|
|
||||||
obj = cls.objects.select_for_update().get(**kwargs)
|
|
||||||
return obj, False
|
|
||||||
except cls.DoesNotExist:
|
|
||||||
# 不存在则创建
|
|
||||||
obj = cls(**kwargs, **defaults)
|
|
||||||
obj.save()
|
|
||||||
return obj, True
|
return obj, True
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
# 发生唯一约束冲突时重试
|
try:
|
||||||
if attempt == 2:
|
# 有别的进程抢先创建了,直接 get
|
||||||
raise
|
obj = cls.objects.get(**kwargs)
|
||||||
time.sleep(0.1 * (attempt + 1))
|
return obj, False
|
||||||
except Exception:
|
except cls.DoesNotExist:
|
||||||
# 其他异常直接抛出
|
# 极端并发情况下 create 和 get 都失败,稍微等一下重试
|
||||||
raise
|
time.sleep(0.001 * (i + 1)) # 微等一下避免竞争
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 最终重试失败(极罕见)
|
||||||
|
obj = cls.objects.get(**kwargs)
|
||||||
|
return obj, False
|
||||||
|
|
||||||
|
|
||||||
def handle_parent(self):
|
def handle_parent(self):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue