> Использовали ли инструменты для асинхронности в Django, например Celery и Redis (Python)

Уровень: senior · Роль: backend · Язык: Python · Категория: Технические вопросы

Компании: Стилсофт, АО НПФ Будущее, inpglobal

Стек: Redis, Python

> Пример ответа

Короткий ответ

Да, в продакшене я использовал связку Celery + Redis для асинхронных задач: отправка email, генерация отчётов, обработка webhook'ов, периодические задачи через celery beat. Redis выступал как broker и backend для результатов. Также использовал Redis напрямую для кэширования и rate limiting. Важно понимать trade-off: Celery добавляет инфраструктурную сложность, поэтому для простых случаев достаточно django-q или даже threading.

Подробное объяснение

Celery - это распределённая очередь задач, которая позволяет выносить тяжёлые операции из request-response цикла. Redis в этой связке выполняет две роли:

  • Broker - хранит очередь сообщений, откуда воркеры забирают задачи
  • Result backend - хранит результаты выполнения задач (если включён)

Ключевые компоненты:

  • Worker - процесс, который выполняет задачи
  • Beat - планировщик периодических задач (cron-аналог)
  • Task - функция, обёрнутая декоратором @shared_task

Redis также полезен сам по себе:

  • кэширование через django-redis
  • rate limiting (например, через django-ratelimit)
  • pub/sub для real-time уведомлений
  • хранение временных данных (сессии, очереди)

Важные нюансы:

  • Идемпотентность задач - повторное выполнение не должно ломать данные
  • Retry policy - настройка повторных попыток при сбоях
  • Visibility timeout - защита от зависших задач
  • Мониторинг - flower или celery-exporter для Prometheus

На практике

В реальном проекте я использовал Celery для:

  • отправка transactional email (через celery + django-anymail)
  • генерация PDF-отчётов по расписанию
  • обновление поискового индекса после изменения моделей
  • обработка загрузки файлов (resize изображений)

Redis использовал для:

  • кэширование queryset'ов с инвалидацией по сигналам
  • хранение счётчиков просмотров (INCR)
  • реализация distributed lock для конкурентных операций

Настройка в settings.py:

PYTHON
CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'
CELERY_TASK_SERIALIZER = 'json'
CELERY_TASK_TIME_LIMIT = 300

Пример кода

PYTHON
# tasks.py
from celery import shared_task
from django.core.mail import send_mail
@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def send_welcome_email(self, user_email):
try:
send_mail(
'Welcome!',
'Thanks for signing up.',
'from@example.com',
[user_email],
fail_silently=False,
)
except Exception as exc:
raise self.retry(exc=exc)
# views.py
def register(request):
# ... создание пользователя
send_welcome_email.delay(user.email)
return HttpResponse(status=201)
# периодическая задача
@shared_task
def cleanup_old_sessions():
Session.objects.filter(expire_date__lt=timezone.now()).delete()
# celery.py (в проекте)
from celery import Celery
from celery.schedules import crontab
app = Celery('myproject')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
app.conf.beat_schedule = {
'cleanup-sessions-every-day': {
'task': 'myapp.tasks.cleanup_old_sessions',
'schedule': crontab(hour=3, minute=0),
},
}

Как отвечать на собеседовании

Начни с конкретного примера из практики: какую задачу решал и почему выбрал Celery. Затем покажи понимание архитектуры: broker, worker, beat. Упомяни альтернативы (django-q, arq, dramatiq) и когда они уместнее. Обязательно скажи про подводные камни: потеря задач, дублирование, мониторинг. Если спросят про Redis отдельно - расскажи про кэширование, rate limiting, pub/sub. Покажи, что понимаешь разницу между синхронным и асинхронным выполнением и когда что применять.

Что проверяет интервьюер

  • Понимание асинхронной архитектуры и места Celery в ней
  • Практический опыт: настройка, деплой, мониторинг
  • Умение проектировать надёжные задачи (retry, idempotency)
  • Знание Redis как самостоятельного инструмента
  • Способность объяснить trade-off'ы и альтернативы
  • Понимание lifecycle задачи: от вызова до выполнения

Типичные ошибки

  • Утверждение, что Celery - единственный способ асинхронности в Django
  • Непонимание разницы между broker и result backend
  • Игнорирование идемпотентности - задачи могут выполниться дважды
  • Отсутствие настройки time limits - зависшие задачи блокируют воркеры
  • Использование Celery для простых задач, где достаточно cache.set или сигналов
  • Незнание, как масштабировать воркеры (concurrency, prefetch multiplier)
  • Путаница между delay() и apply_async() с явными параметрами
  • Забывают про visibility timeout в Redis - задача может быть взята повторно после сбоя воркера

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью