Files
octopus/myproject/inventory/tasks.py

86 lines
3.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
from celery import shared_task
from django.utils import timezone
from django.db.models import Q
import logging
from django_tenants.utils import get_tenant_model, schema_context
logger = logging.getLogger(__name__)
@shared_task
def cleanup_expired_cart_locks():
"""
Периодическая задача для очистки истекших блокировок корзины.
Освобождает витринные комплекты, которые были добавлены в корзину,
но блокировка истекла (timeout 30 минут).
Запускается каждые 5 минут (настроить в celery beat schedule).
Проходит по всем тенантам.
Returns:
dict: Статистика очистки {
'released_count': int, # Общее количество освобожденных блокировок
'details': list # Детали по каждому тенанту
}
"""
Tenant = get_tenant_model()
overall_stats = {
'released_count': 0,
'details': []
}
# Проходим по всем тенантам (кроме public)
# Public схема не содержит бизнес-данных (корзины, резервы)
tenants = Tenant.objects.exclude(schema_name='public')
for tenant in tenants:
try:
with schema_context(tenant.schema_name):
from inventory.models import Reservation
# Находим все резервы с истекшей блокировкой
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')
count = expired_locks.count()
if count > 0:
affected_kits = list(
expired_locks.values_list('product_kit_id', flat=True).distinct()
)
logger.info(
f"[{tenant.schema_name}] Очистка истекших блокировок: {count} резервов"
)
# Очищаем блокировки
expired_locks.update(
cart_lock_expires_at=None,
locked_by_user=None,
cart_session_id=None
)
overall_stats['released_count'] += count
overall_stats['details'].append({
'tenant': tenant.schema_name,
'released': count,
'kits': affected_kits
})
except Exception as e:
# Логируем ошибку, но не прерываем обработку других тенантов
logger.error(f"[{tenant.schema_name}] Ошибка при очистке блокировок: {e}", exc_info=True)
overall_stats['details'].append({
'tenant': tenant.schema_name,
'error': str(e)
})
if overall_stats['released_count'] > 0:
logger.info(f"Общая очистка блокировок завершена: {overall_stats}")
return overall_stats