Пайплайны по расписанию с историей, повторами и логами
Добавьте cron-триггер в пайплайн для повторяющейся работы: выражения проверяются при сохранении, история выполнения видна рядом с HTTP-вызовами, повторы настраиваются, а секреты и логи общие с API-функциями — без отдельного сервиса расписаний или crontab на VPS.
Обновлено: 2026-10-11
Кратко
Суть ответа
Пайплайны по расписанию с историей, повторами и логами. Каждая задача по расписанию — пайплайн с cron-триггером. Платформа проверяет cron-выражение при сохранении, хранит время следующего запуска на пайплайн и создаёт запись вызова на каждое выполнение — всё доступно без SSH. Выбор лидера через advisory-lock в Postgres гарантирует, что каждое расписание срабатывает на одном узле, даже если рабочих узлов несколько.
Когда подходит
- Ночной ETL, ежечасная синхронизация, недельные отчёты, ротация сертификатов
- Любая повторяющаяся задача, которой нужны видимая история прогонов и повторы
На что обратить внимание
- Когда состояние задач живёт на одном хосте, каждый деплой может сбросить расписание, каждая SSH-сессия — потенциальный выстрел в ногу, а каждая замена VPS — перечитывание двухлетнего runbook.
- Секреты в файлах
.envна сервере — кошмар для аудита; записи crontab не версионируются вместе с кодом приложения.
Нагрузка и где ломается
Тихие сбои традиционных задач по расписанию
- Crontab на VPS: вывод уходит в почту root, которую никто не читает; повторов при сбое нет
- systemd timers: надёжнее, но логи разбросаны, секреты вручную, истории нет
- Kubernetes CronJob: правильные примитивы, но накладные расходы кластера для небольших команд
Задачи по расписанию падают тихо чаще любого другого примитива бэкенда. Задача крутится на VPS, скрипт выходит с ненулевым кодом, ошибка уходит в почтовый спул — и никто не знает, пока данные не устареют на три дня.
Компромиссы
Почему crontab на сервере не переживает рост команды
Когда состояние задач живёт на одном хосте, каждый деплой может сбросить расписание, каждая SSH-сессия — потенциальный выстрел в ногу, а каждая замена VPS — перечитывание двухлетнего runbook.
Секреты в файлах .env на сервере — кошмар для аудита; записи crontab не версионируются вместе с кодом приложения.
Как помогает Inquir
Пайплайны по расписанию как полноценная часть платформы
Каждая задача по расписанию — пайплайн с cron-триггером. Платформа проверяет cron-выражение при сохранении, хранит время следующего запуска на пайплайн и создаёт запись вызова на каждое выполнение — всё доступно без SSH. Выбор лидера через advisory-lock в Postgres гарантирует, что каждое расписание срабатывает на одном узле, даже если рабочих узлов несколько.
Планировщик опрашивает каждые 30 секунд (минимальный интервал — 1 минута), поэтому срабатывание укладывается в ~30 с от запланированного времени. Задачи по расписанию делят секреты рабочего пространства и тот же стек наблюдаемости, что HTTP-маршруты: ночной ETL, недельные отчёты и ежечасная синхронизация видны в истории выполнения рядом с вызовами вебхуков и API.
Сравнение
crontab, systemd timers, Kubernetes CronJob и Inquir
Выбор планировщика зависит от зрелости эксплуатации и того, где уже живёт остальной стек. Таблица сравнивает четыре типичных подхода к повторяющейся бэкенд-работе — не edge-cron и не субсекундные тики.
| Критерий | crontab | systemd timers | Kubernetes CronJob | Пайплайны Inquir по расписанию |
|---|---|---|---|---|
| Настройка и сопровождение | Правка crontab на хосте; выражение не проверяется при сохранении | Unit- и timer-файлы; надёжнее срабатывание, но упаковка всё ещё на уровне хоста | YAML-манифесты и работающий кластер — даже для одной ночной задачи | Cron на триггере пайплайна; выражение проверяется при сохранении |
| История запусков | Перенаправление stdout в файл или почту root — без структурированного аудита | journalctl по unit; при росте числа задач — grep по сервисам | Логи подов и статус Job; хранение зависит от стека логирования кластера | Записи вызовов рядом с HTTP-выполнениями — доступны без SSH |
| Повторы при сбое | Нет — следующее срабатывание и есть единственный неявный повтор | OnFailure= может перезапустить unit; политики повторов на запуск в продуктовом UI нет | backoffLimit у Job; настраивается в манифесте, не рядом с историей API | Число повторов и задержка на каждом шаге пайплайна |
| Секреты | .env на сервере или inline в shell — общие для всех задач на хосте | EnvironmentFile в unit; ротация по-прежнему вручную на каждом хосте | Kubernetes Secrets — нативно для кластера, но отдельно от авторизации на шлюзе приложения | Секреты рабочего пространства, общие с HTTP-маршрутами — без параллельного .env на сервере |
| Изоляция между задачами | Один UNIX-пользователь и окружение интерпретатора — конфликты зависимостей типичны | Можно запускать от разных пользователей; всё равно одна машина, общее ядро | Под на запуск — сильная изоляция, когда кластер уже оправдан | Контейнер на вызов — та же модель изоляции, что у синхронных HTTP-обработчиков |
| Версионирование вместе с кодом | Строки crontab часто живут вне пайплайна деплоя | Unit-файлы могут лежать в git; расхождение между хостами всё равно случается | Манифесты в git/GitOps — отлично, когда K8s уже control plane | Бандлы функций и конфиг пайплайна версионируются вместе с деплоем платформы |
| Многошаговые процессы | Shell-скрипты с цепочкой команд — непрозрачные точки сбоя | Отдельные unit или bash в ExecStart — ручная оркестрация | Один контейнер на CronJob; для DAG нужны Argo/Workflows или аналоги | Графы пайплайнов с рёбрами — extract, transform, load как узлы-функции |
| Перекрытие / долгие прогоны | Ручной flock или надежда — параллельные запуски портят общее состояние | Настройки concurrency на unit — логику всё равно пишете сами в обработчике | concurrencyPolicy Forbid/Replace в спецификации CronJob | Защита skip-if-running и ключи идемпотентности в обработчике или в дизайне пайплайна |
| Когда уместно | Одна VPS, один инженер, скрипты уже работают и редко падают | Linux-команды эксплуатации на systemd, готовые копать journal | Продукт уже на Kubernetes с GitOps и логированием кластера | Пайплайны по расписанию и REST на одной платформе — история и повторы без YAML кластера |
Что вы получаете
Возможности расписаний пайплайнов
Проверка cron-выражений
Выражения проверяются при сохранении пайплайна — некорректная запись падает сразу, а не тихо на следующем тике.
История прогонов и логи
Каждое выполнение по расписанию создаёт запись вызова: время старта, длительность, статус завершения, выходы шагов. Доступно без SSH.
Повторы и защита от наложения
Настройте число попыток и задержку на шаг. Добавьте ключи идемпотентности для защиты от наложения, когда долгая задача выходит за свой интервал.
Общие секреты
Задачи по расписанию используют те же секреты рабочего пространства, что HTTP-маршруты, — без параллельных файлов .env на сервере.
Что дальше
Как задать расписание пайплайна в Inquir
Написать обработчик задачи
Обычная функция. Секреты — из переменных окружения; на каждый шаг возвращайте структурированный выход.
Добавить расписание пайплайна
В визуальном редакторе пайплайнов соедините узел cronTrigger с узлом-функцией и введите cron-выражение. Сохраните пайплайн, чтобы проверить расписание.
Следить за историей прогонов
Откройте историю выполнения: каждый запуск, длительность и выход — без доступа по SSH.
Пример кода
Ночная синхронизация с курсором
Обработчик по расписанию читает курсор из окружения, забирает инкрементальные обновления, идемпотентно делает upsert и возвращает новый курсор для следующего запуска.
export async function handler(event) { // event.trigger?.type === 'schedule' when fired by a cronTrigger node const since = process.env.SYNC_CURSOR ?? new Date(Date.now() - 86_400_000).toISOString(); const records = await source.fetchUpdatedSince(since); if (records.length === 0) return { synced: 0, cursor: since }; await destination.upsertBatch(records); // idempotent by record ID const newCursor = records.at(-1)?.updatedAt ?? since; // Store cursor for next run (update env var or external store) return { synced: records.length, cursor: newCursor }; }
Когда подходит
Пайплайны по расписанию подходят для…
Когда это уместно
- Ночной ETL, ежечасная синхронизация, недельные отчёты, ротация сертификатов
- Любая повторяющаяся задача, которой нужны видимая история прогонов и повторы
Когда лучше выбрать другое
- Расписания чаще раза в минуту — минимальный интервал cron 1 минута; планировщик срабатывает в пределах ~30 с от запланированного времени, но точность до секунды не гарантирует
Частые вопросы
Частые вопросы
Может ли одна функция обслуживать HTTP и пайплайн по расписанию?
Да. Укажите тот же ID функции в узле-функции пайплайна и в HTTP-маршруте шлюза. Cron-триггер запускает пайплайн, который вызывает этот шаг.
В каком часовом поясе интерпретируются cron-выражения?
Для продакшен-расписаний используйте UTC, если требования не привязаны жёстко к рабочим часам по местному времени. Зафиксируйте допущение о часовом поясе в названии пайплайна.
Каков минимальный интервал cron?
Одна минута. Планировщик опрашивает каждые 30 секунд, поэтому реальное срабатывание может отстать от запланированной минуты до 30 секунд. Не рассчитывайте на интервалы короче 1 минуты и на точность до секунды.
Что если запуск длится дольше интервала?
Используйте ключи идемпотентности, распределённые блокировки или проверку «пропустить, если уже идёт» внутри обработчика, чтобы перекрывающиеся запуски не портили общее состояние. Для идемпотентных задач курсор делает наложение безопасным по построению.
Можно ли проверить задачу до следующего запуска по расписанию?
Да — вызовите функцию напрямую через шлюз или консоль. Это проверяет обработчик, а не расписание пайплайна или весь процесс.