"""Постановка задачи `send_invitations` в очередь Celery. Отправляет задачу по имени через голый Celery-клиент (`broker_url` без `backend`) — тот же приём, что `services/pipeline_producer.py`: backend не импортирует пакет `workers` (инвариант разделения слоёв, см. докстринг `pipeline_producer.py`). Задача регистрируется и обрабатывается в `workers/tasks/invitations.py` (блок C). """ import uuid from celery import Celery from core.config import get_settings SEND_INVITATIONS_TASK_NAME = "workers.tasks.invitations.send_invitations" NOTIFY_QUEUE = "notify" def enqueue_invitations(conference_id: uuid.UUID, *, emails: list[str] | None = None) -> None: """Поставить в очередь `notify` рассылку .ics-приглашений на конференцию `conference_id`. `emails=None` — получатели по умолчанию (владелец + для закреплённых участники прошлых сеансов, см. `workers/tasks/invitations.py`); явный список — ручная рассылка администратором. Задача сама идемпотентна (журнал `email_deliveries(kind='invitation')` без unique, повтор постановки максимум продублирует письмо). Очередь передаётся явно (`queue=NOTIFY_QUEUE`): этот клиент — отдельный экземпляр `Celery` без `task_routes` из `workers/celery_app.py` (тот маршрут действует только внутри процесса воркера, который его импортирует), поэтому без явного параметра задача ушла бы в дефолтную очередь `celery` — тот же приём, что `TRANSCRIPTION_QUEUE` в `pipeline_producer.py`. """ settings = get_settings() client = Celery("vidconf-producer", broker=settings.redis_url) client.send_task( SEND_INVITATIONS_TASK_NAME, args=[str(conference_id), emails], queue=NOTIFY_QUEUE )