> Как работает периодический таск, который читает таблицу уведомлений и отправляет их? (Python)
Уровень: senior · Роль: backend · Язык: Python · Категория: Технические вопросы
Компании: HeadHunter
Стек: Python
> Пример ответа
Периодический таск для чтения таблицы уведомлений и их отправки обычно реализуется с помощью фонового воркера (например, Celery Beat, APScheduler или простого threading.Timer). Основная логика выглядит так:
- Планировщик запускает задачу с заданным интервалом (например, каждые 10 секунд).
- Запрос к БД: выбираются уведомления со статусом
pendingилиnew, которые ещё не были отправлены. Часто добавляется условие по времени (например,scheduled_at <= NOW()). - Блокировка (опционально): чтобы избежать дублирования при параллельных запусках, используется
SELECT ... FOR UPDATEили оптимистичная блокировка через полеversion. - Отправка: для каждого уведомления вызывается соответствующий канал (email, push, SMS и т.д.). Ошибки логируются, а статус записи меняется на
failedилиsent. - Обновление статуса: после успешной отправки запись помечается как
sent, чтобы повторно не обрабатываться.
Пример на Python с использованием APScheduler и SQLAlchemy:
PYTHONfrom apscheduler.schedulers.background import BackgroundSchedulerfrom sqlalchemy import select, updatefrom your_app.models import Notification, NotificationStatusfrom your_app.services import send_notificationdef process_notifications():with db_session() as session:# Выбираем неотправленные уведомления с блокировкой строкstmt = select(Notification).where(Notification.status == NotificationStatus.PENDING).with_for_update(skip_locked=True).limit(100)notifications = session.execute(stmt).scalars().all()for notif in notifications:try:send_notification(notif)notif.status = NotificationStatus.SENTexcept Exception as e:notif.status = NotificationStatus.FAILEDnotif.error_message = str(e)session.commit()# Настройка планировщикаscheduler = BackgroundScheduler()scheduler.add_job(process_notifications, 'interval', seconds=10)scheduler.start()
Важные нюансы:
- Используйте
skip_locked=Trueв блокировке, чтобы разные воркеры не ждали друг друга. - Ограничивайте количество записей за один раз (
LIMIT), чтобы не перегружать память. - Для высокой нагрузки рассмотрите очередь (RabbitMQ, Redis) вместо прямого опроса БД.
- Мониторьте количество уведомлений в статусе
pending- если оно растёт, увеличьте частоту или масштабируйте воркеры.
> Похожие задачи по Python
Что такое дедлоки?
Какие решения кроме паттерна outbox помогают гарантировать выполнение асинхронных задач?
Будет ли конкуренция при выполнении периодического таска, который читает и обновляет записи в таблице?
Работали ли с CDC системами, например Debezium, для мониторинга изменений в базе данных и интеграции с асинхронными процессами?
> Похожие задачи по backend
Что такое дедлоки?
Какие решения кроме паттерна outbox помогают гарантировать выполнение асинхронных задач?
Будет ли конкуренция при выполнении периодического таска, который читает и обновляет записи в таблице?
Работали ли с CDC системами, например Debezium, для мониторинга изменений в базе данных и интеграции с асинхронными процессами?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью