from datetime import timedelta from django.conf import settings from django.db import migrations, models import django.db.models.deletion from django.utils import timezone def _retry_dedupe_key(job): suffix = f":definitive-delivery-retry:{job.pk}" return f"{job.dedupe_key[:200-len(suffix)]}{suffix}" def queue_historical_definitive_delivery_retries(apps, schema_editor): """Queue each old, definitively expired individual staff-created SMS once.""" NotificationJob = apps.get_model("notifications", "NotificationJob") delay = getattr(settings, "SMS_DEFINITIVE_DELIVERY_RETRY_AFTER_SECONDS", 2700) stagger = getattr(settings, "SMS_HISTORICAL_DELIVERY_RETRY_STAGGER_SECONDS", 30) now = timezone.now() sources = NotificationJob.objects.filter( channel="SMS", event_type="STAFF_TICKET_CREATED", status="SENT", ticket__group_dispatch__isnull=True, delivery_status="EXPIRED", delivery_next_check_at__isnull=True, delivery_retry_source__isnull=True, ).order_by("id") queued = 0 for source in sources.iterator(): if NotificationJob.objects.filter(delivery_retry_source_id=source.pk).exists(): continue sent_at = source.sent_at or source.created_at due = max(sent_at + timedelta(seconds=delay), now + timedelta(seconds=(queued + 1) * stagger)) NotificationJob.objects.create( channel=source.channel, event_type=source.event_type, customer_id=source.customer_id, staff_user_id=source.staff_user_id, ticket_id=source.ticket_id, payload=source.payload, status="PENDING", attempts=0, next_attempt_at=due, dedupe_key=_retry_dedupe_key(source), delivery_retry_source_id=source.pk, ) queued += 1 class Migration(migrations.Migration): dependencies = [("notifications", "0012_supervisor_sms_template")] operations = [ migrations.AddField( model_name="notificationjob", name="delivery_is_final", field=models.BooleanField(default=False), ), migrations.AddField( model_name="notificationjob", name="delivery_retry_source", field=models.OneToOneField( blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name="delivery_retry_job", to="notifications.notificationjob", ), ), migrations.RunPython(queue_historical_definitive_delivery_retries, migrations.RunPython.noop), ]