Features: 1) Add retry mechanism with exponential backoff for saving attributes to handle deadlocks.

Fixes: 1) Remove unused `traceback` import; 2) Add missing import for `OperationalError`; 3) Prevent redundant saves for unchanged attributes.

Extra: 1) Simplify attribute save logic and improve efficiency; 2) Code cleanup for better readability.
This commit is contained in:
Egor Pavlovich Gorbunov 2025-10-19 01:44:28 +03:00
parent 1fed75584e
commit 2712ccdeb7

View file

@ -1,6 +1,6 @@
import gzip import gzip
import json import json
import traceback import time
from contextlib import suppress from contextlib import suppress
from datetime import datetime from datetime import datetime
from decimal import Decimal from decimal import Decimal
@ -14,6 +14,7 @@ from django.conf import settings
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.db import IntegrityError, transaction from django.db import IntegrityError, transaction
from django.db.models import QuerySet from django.db.models import QuerySet
from django.db.utils import OperationalError
from core.elasticsearch import process_system_query from core.elasticsearch import process_system_query
from core.models import ( from core.models import (
@ -446,15 +447,27 @@ class AbstractVendor:
) )
except Attribute.MultipleObjectsReturned: except Attribute.MultipleObjectsReturned:
attribute = Attribute.objects.filter(name=key, group=attr_group).order_by("uuid").first() # type: ignore [assignment] attribute = Attribute.objects.filter(name=key, group=attr_group).order_by("uuid").first() # type: ignore [assignment]
fields_to_update: list[str] = []
if not attribute.is_active:
attribute.is_active = True attribute.is_active = True
fields_to_update.append("is_active")
if attribute.value_type != attr_value_type:
attribute.value_type = attr_value_type attribute.value_type = attr_value_type
attribute.save() fields_to_update.append("value_type")
if fields_to_update:
for attempt in range(5):
try:
attribute.save(update_fields=fields_to_update)
break
except OperationalError as e:
if "deadlock detected" in str(e):
time.sleep(0.1 * (2**attempt))
continue
raise
except IntegrityError: except IntegrityError:
async_logger.warning(f"IntegrityError while processing attribute {key!r}...") async_logger.warning(f"IntegrityError while processing attribute {key!r}...")
return return
attribute.save()
if not is_created: if not is_created:
return return