⏱️ CRON при репликации сервиса: когда он внезапно запускается дважды
Когда у тебя один инстанс сервиса — cron-задачи живут спокойной жизнью: раз в минуту/час/день отработали — и всё
Но как только появляется горизонтальное масштабирование, начинается цирк: один и тот же cron внезапно запускается на всех репликах
Результат — задвоение задач, дубль-отправки в очередь, лишние запросы в БД, гонки, broken idempotency.
Разбираемся, как это контролировать
🙃 Способы синхронизации CRON между репликами
1) Distributed lock (рекомендуется)
Ты заранее пытаешься взять “маркер лидерства”
Кто взял — тот и выполняет cron. Остальные ждут
Варианты реализации:
— Redis + RedlockСтандарт: быстрая блокировка с TTL → если под умер, блокировка сама освободится
— PostgreSQL advisory locksSELECT pg_try_advisory_lock(12345)
Если вернул true, ты — лидер
— PostgreSQL row-level / table-level locks
Простой механизм: лочишь строку “task_name = cleanup_daily”
2) Leader election (лидер выбирается автоматически)
Идея: из всех реплик выбирается одна основная, она и запускает cron.
Варианты:
— Kubernetes leader election через Lease API
Удобно для Cron внутри подов
— Consul / Etcd лидер-электоры
Более enterprise-решение.
3) Cron вынести наружу (лучший вариант для сложных систем)
Перенести все периодические задачи в:
— Kubernetes CronJob
Самый распространённый вариант.
— Airflow / Temporal / BullMQ Scheduler
Если задач много и они взаимосвязаны.
— Dedicated scheduler service
Минус: иногда оверхед для небольших проектов
4) Idempotency + мягкая синхронизацияЕсли не можешь/не хочешь бороться с параллельностью —
просто проектируешь cron так, чтобы дубликат не ломал логику
Подходы:
— В БД держать processed_at, а cron проверяет “ещё не обработано?”.
— Все действия писать через UPSERT / ON CONFLICT DO NOTHING.
— Слать команды в очередь, где есть idempotency-key.
🚀 Пост Guru Node.js:
@DemetraIT