# -*- coding: utf-8 -*- from celery import shared_task from django.utils import timezone from django.db.models import Q import logging logger = logging.getLogger(__name__) @shared_task def cleanup_expired_cart_locks(): """ Периодическая задача для очистки истекших блокировок корзины. Освобождает витринные комплекты, которые были добавлены в корзину, но блокировка истекла (timeout 30 минут). Запускается каждые 5 минут (настроить в celery beat schedule). Returns: dict: Статистика очистки { 'released_count': int, # Количество освобожденных блокировок 'affected_kits': list # ID освобожденных комплектов } """ from inventory.models import Reservation try: # Находим все резервы с истекшей блокировкой expired_locks = Reservation.objects.filter( Q(cart_lock_expires_at__lte=timezone.now()) & Q(cart_lock_expires_at__isnull=False) & Q(status='reserved') ).select_related('product_kit', 'locked_by_user') # Собираем статистику перед очисткой affected_kits = list( expired_locks.values_list('product_kit_id', flat=True).distinct() ) released_count = expired_locks.count() # Логируем информацию о блокировках if released_count > 0: logger.info( f"Очистка истекших блокировок: {released_count} резервов, " f"{len(affected_kits)} комплектов" ) for lock in expired_locks[:10]: # Логируем первые 10 для отладки kit_name = lock.product_kit.name if lock.product_kit else 'N/A' user_name = lock.locked_by_user.username if lock.locked_by_user else 'N/A' logger.debug( f"Освобождение блокировки: комплект='{kit_name}', " f"пользователь='{user_name}', " f"истекла={lock.cart_lock_expires_at}" ) # Очищаем блокировки expired_locks.update( cart_lock_expires_at=None, locked_by_user=None, cart_session_id=None ) result = { 'released_count': released_count, 'affected_kits': affected_kits, 'timestamp': timezone.now().isoformat() } if released_count > 0: logger.info(f"Очистка завершена успешно: {result}") return result except Exception as e: logger.error(f"Ошибка при очистке истекших блокировок: {str(e)}", exc_info=True) return { 'released_count': 0, 'affected_kits': [], 'error': str(e) }