dbt
JuniorКак развернуть dbt так, чтобы он реально запускался по расписанию в проде?
У самого dbt нет планировщика — dbt run просто выполняется один раз и завершается. Заставить его запускаться автоматически, надёжно, по расписанию — это целиком решение, которое вы принимаете вне dbt.
Запуск `dbt build` с вашего ноутбука доказывает, что проект работает. Заставить его запускаться каждое утро в 6, повторять попытку при временных ошибках хранилища и кого-то оповещать, когда это не сработало — это деплой, и dbt намеренно не имеет мнения о том, как вы это делаете.
Три реальных варианта и что каждый берёт на себя
dbt Cloud целиком владеет планировщиком, историей прогонов и логикой повторов — вы настраиваете расписание в его UI, и он делает остальное, ценой работы внутри инфраструктуры dbt Labs, а не вашей. Свой оркестратор (Airflow, Dagster, Prefect) обращается с прогоном dbt как с одной задачей в большем DAG — правильный выбор, когда dbt — один шаг среди нескольких (извлечение, загрузка, трансформация dbt, downstream-экспорт), которые нужно упорядочить и которые зависят друг от друга, а не просто запускать по часам. Обычный cron плюс раннер CI (запланированный workflow GitHub Actions, cron-задача на VM) — самый простой вариант и полностью достаточный для проекта без межинструментальных зависимостей — просто не тянитесь к нему, как только вам реально понадобятся повторы, оповещения или зависимости на уровне DAG, которые он не даёт бесплатно.
За что вы отвечаете независимо от выбора
Две вещи, которые dbt реально не берёт на себя ни в одной из этих настроек. Во-первых, креды —
profiles.yml (или конфиг подключения dbt Cloud) всё ещё нуждается в реальных кредах к
хранилищу там, где прогон реально выполняется, следуя тому же паттерну env_var()-а-не-
хардкода независимо от планировщика. Во-вторых, оповещение о сбое — упавший dbt build
выходит с ненулевым кодом, но никого не будят, если окружающий оркестратор не настроен проверять этот код
выхода и оповещать. У dbt Cloud это встроено; Airflow/Dagster нужно настроить это как часть DAG; обычному
cron нужно прикрутить это явно (обёрточный скрипт, проверяющий $? и обращающийся к
Slack/PagerDuty или аналогу).
Ошибка, для предотвращения которой существует этот раздел: cron-задача, которая тихо перестаёт
запускаться (передеплоенная VM без crontab, случайно отключённый файл CI-workflow), не выдаёт вообще
никакой ошибки — не упавший прогон, а просто отсутствие прогона. Проверки freshness на таблицах, которые
она должна была обновить (см. статью про freshness в sources.yml), — вот что реально это
ловит, а не сам планировщик.
Где здесь место opti-pipe, а где нет
Ни один из этих выборов планирования не меняет того, что читает opti-pipe — движок правил смотрит на
run_results.json, который любой из этих вариантов производит одинаково, поскольку это
собственный вывод dbt независимо от того, что запустило прогон. Чего он не может сказать — произошёл ли
прогон вообще или по расписанию — это целиком работа слоя деплоя, и стоит проверять независимо (дашборд,
проверка freshness, реальное оповещение), а не считать, что тишина значит «всё в порядке».
Посмотрите, как это выглядит на вашем собственном пайплайне.
Загрузите реальный event log Spark, run_results.json от dbt или экспорт метрик Flink — и получите конкретные рекомендации, которые нужно одобрить, а не ещё одно эмпирическое правило.