feat: Add Docker entrypoint script for application orchestration and implement cleanup for stuck photo processing tasks with improved error handling.
This commit is contained in:
@@ -7,4 +7,4 @@ from .celery import app as celery_app
|
||||
# Для совместимости с командами типа 'celery -A myproject'
|
||||
celery = celery_app
|
||||
|
||||
__all__ = ('celery_app',)
|
||||
__all__ = ('celery_app', 'celery')
|
||||
|
||||
@@ -16,6 +16,7 @@ from django.db import connection
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.core.files.storage import default_storage
|
||||
from django.utils import timezone
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -73,6 +74,12 @@ def process_product_photo_async(self, photo_id, photo_model_class, schema_name):
|
||||
# Сохраняем путь к временному файлу до перезаписи поля image
|
||||
temp_path = photo_obj.image.name
|
||||
|
||||
# КРИТИЧНО: Проверяем что файл существует перед обработкой
|
||||
# Это предотвращает бесполезные retry если файл был удален вручную
|
||||
if not default_storage.exists(temp_path):
|
||||
logger.error(f"[Celery] File does not exist: {temp_path}")
|
||||
raise FileNotFoundError(f"File not found: {temp_path}")
|
||||
|
||||
# Получаем entity type для правильного пути сохранения
|
||||
entity_type = photo_obj.get_entity_type()
|
||||
|
||||
@@ -138,6 +145,35 @@ def process_product_photo_async(self, photo_id, photo_model_class, schema_name):
|
||||
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 FileNotFoundError as exc:
|
||||
# Файл не найден - не имеет смысла повторять task
|
||||
# Это обычно означает что файл был удален до обработки
|
||||
logger.error(f"[Celery] File not found for photo {photo_id} in {schema_name}: {str(exc)}")
|
||||
logger.error(f"[Celery] This usually means the file was deleted before processing. Marking as failed.")
|
||||
|
||||
# Обновляем статус обработки без retry
|
||||
try:
|
||||
from .models.photos import PhotoProcessingStatus
|
||||
status = (PhotoProcessingStatus.objects
|
||||
.filter(photo_id=photo_id, photo_model=photo_model_class)
|
||||
.order_by('-created_at')
|
||||
.first())
|
||||
if status:
|
||||
status.status = 'failed'
|
||||
status.error_message = f"File not found: {str(exc)}"
|
||||
status.completed_at = timezone.now()
|
||||
status.save()
|
||||
logger.info(f"[Celery] Updated PhotoProcessingStatus to 'failed' for photo {photo_id}")
|
||||
except Exception as status_exc:
|
||||
logger.warning(f"[Celery] Could not update PhotoProcessingStatus: {status_exc}")
|
||||
|
||||
return {
|
||||
'status': 'error',
|
||||
'reason': 'file_not_found',
|
||||
'photo_id': photo_id,
|
||||
'error': str(exc)
|
||||
}
|
||||
|
||||
except Exception as exc:
|
||||
logger.error(f"[Celery] Error processing photo {photo_id} in {schema_name}: {str(exc)}",
|
||||
exc_info=True)
|
||||
|
||||
Reference in New Issue
Block a user