From 509561fdb346e534f1564e9833cac3a174de46ac Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Sun, 16 Nov 2025 02:02:15 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B3=D0=BE=D0=BD=D0=BA=D0=B0=20=D0=91?= =?UTF-8?q?=D0=94=20=D0=BF=D1=80=D0=B8=20async=20=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=BA=D0=B5=20=D0=BF=D0=B5=D1=80=D0=B2=D0=BE?= =?UTF-8?q?=D0=B3=D0=BE=20=D1=84=D0=BE=D1=82=D0=BE=20=D0=BA=D0=BE=D0=BC?= =?UTF-8?q?=D0=BF=D0=BB=D0=B5=D0=BA=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Добавлен retry на 5 сек при DoesNotExist для ожидания коммита транзакции - temp_path сохраняется в PhotoProcessingStatus.result_data при постановке задачи - При окончательной неудаче not_found удаляется осиротевший temp файл - Предотвращает накопление temp файлов при гонке создания фото --- myproject/products/models/photos.py | 3 ++- myproject/products/tasks.py | 21 +++++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/myproject/products/models/photos.py b/myproject/products/models/photos.py index 15aed86..ef1e3fd 100644 --- a/myproject/products/models/photos.py +++ b/myproject/products/models/photos.py @@ -102,7 +102,8 @@ class BasePhoto(models.Model): photo_id=self.pk, photo_model=photo_model_class, status='pending', - task_id=task_result.id + task_id=task_result.id, + result_data={'temp_path': getattr(temp_image, 'name', None)} ) except ImportError: diff --git a/myproject/products/tasks.py b/myproject/products/tasks.py index 0ecb113..45718fa 100644 --- a/myproject/products/tasks.py +++ b/myproject/products/tasks.py @@ -101,9 +101,26 @@ def process_product_photo_async(self, photo_id, photo_model_class, schema_name): } } - except PhotoModel.DoesNotExist: + except PhotoModel.DoesNotExist as e: logger.error(f"[Celery] Photo {photo_id} not found in schema {schema_name}") - return {'status': 'error', 'reason': 'not_found', 'photo_id': photo_id} + # Retry briefly to allow DB transaction to commit (race condition on first photo) + try: + raise self.retry(exc=e, countdown=5) + except self.MaxRetriesExceededError: + # Final failure: attempt to delete the orphan temp file if we recorded it + try: + from .models.photos import PhotoProcessingStatus + status = (PhotoProcessingStatus.objects + .filter(photo_id=photo_id, photo_model=photo_model_class) + .order_by('-created_at') + .first()) + temp_path = (status.result_data or {}).get('temp_path') if status else None + if temp_path and default_storage.exists(temp_path): + default_storage.delete(temp_path) + logger.info(f"[Celery] Deleted temp file (not_found): {temp_path}") + except Exception as del_exc: + logger.warning(f"[Celery] Could not delete temp file for photo {photo_id} on not_found: {del_exc}") + return {'status': 'error', 'reason': 'not_found', 'photo_id': photo_id} except Exception as exc: logger.error(f"[Celery] Error processing photo {photo_id} in {schema_name}: {str(exc)}",