Ограничения и особенности сравнения состояния
Метод выбора state: — это мощная функция с множеством сложностей. Ниже приведены некоторые соображения при настройке автоматизированных задач, использующих сравнение состояний.
Сиды
dbt сохраняет хэш-файл seed-файлов размером менее 1 МиБ. Если содержимое этих seed-файлов изменено, seed будет включен в state:modified.
Если seed-файл больше 1 МиБ, dbt не может сравнить его содержимое и выдаст предупреждение. Вместо этого dbt будет использовать только путь к файлу seed для обнаружения изменений. Если путь к файлу изменился, seed будет включен в state:modified; если нет, то не будет.
Макросы
dbt пометит как измененные все ресурсы, которые зависят от измененного макроса или от макроса, который зависит от измененного макроса.
Переменные
Если модель использует var или env_var в своём определении, dbt не может определить такую зависимость (lineage) таким образом, чтобы включить модель в state:modified из‑за изменения значения var или env_var. При этом модель, скорее всего, будет помечена как изменённая, если изменение значения переменной приводит к другой конфигурации.
Тесты
Команда dbt test -s state:modified будет включать как:
- тесты, которые выбирают из нового/измененного ресурса
- тесты, которые сами по себе новые или измененные
Пока вы добавляете или изменяете тесты одновременно с добавлением или изменением ресурсов (моделей, seed-файлов, снимков), из которых они выбирают, все должно работать так, как вы ожидаете, с "простым" выбором состояния:
dbt run -s "state:modified"
dbt test -s "state:modified"
Однако это может усложниться. Если вы добавите новый тест без изменения его базовой модели или добавите тест, который выбирает из новой модели и старой неизмененной, вам может понадобиться протестировать модель, не запустив ее сначала.
Вы можете отложить ссылки на вышестоящие элементы при тестировании. Например, если тест выбирает из модели, которая не существует как объект базы данных в вашей текущей среде, dbt обратится к другой среде — той, которая определена в вашем манифесте состояния. Это позволяет использовать "простой" выбор состояния без риска сбоя запроса, но может иметь неожиданные последствия для тестов с несколькими родителями. Например, если у вас есть тест relationships, который зависит от одной измененной модели и одной неизмененной, запрос теста будет выбирать данные "между" двумя разными средами. Если вы ограничиваете или выбираете данные в разработке и CI, может не иметь смысла проверять целостность ссылок, зная, что есть большая вероятность несоответствия.
Если вы часто используете тесты relationships или тесты данных, или часто добавляете тесты без изменения их базовых моделей, рассмотрите возможность настройки критериев выбора для вашей CI-задачи. Например:
dbt run -s "state:modified"
dbt test -s "state:modified" --exclude "test_name:relationships"
Перезаписывает manifest.json
dbt перезаписывает файл manifest.json во время парсинга. Это означает, что если вы ссылаетесь на --state из директории target/, вы можете столкнуться с предупреждением о том, что сохранённый manifest не найден.
Во время следующего запуска задания dbt выполняет последовательность шагов, которая и приводит к проблеме. Сначала он перезаписывает target/manifest.json до того, как файл может быть использован для определения изменений. Затем, когда dbt пытается снова прочитать target/manifest.json, чтобы обнаружить изменения, он ничего не находит, поскольку предыдущее состояние уже было перезаписано или удалено.
Избегайте указания одинакового пути для --state и --target-path при использовании функций, зависящих от состояния, таких как --defer и state:modified, так как это может привести к неидемпотентному поведению и результат будет не таким, как ожидается.
Рекомендация
Чтобы manifest.json не перезаписывался до того, как dbt прочитает его для определения изменений, обновите ваш workflow одним из следующих способов:
-
Переместите
manifest.jsonв отдельную папку (например,state/) после того, как dbt сгенерирует его в папкеtarget/. Это гарантирует, что dbt будет ссылаться на корректно сохранённое состояние, вместо сравнения текущего состояния с только что перезаписанной версией. Это также помогает избежать проблем, возникающих при указании--stateи--target-pathна одну и ту же директорию, что может приводить к неидемпотентному поведению. -
Записывайте manifest в другой
--target-pathна этапе сборки (когда dbt генерируетtarget/manifest.json) или до того, как он будет перезаписан во время выполнения job, чтобы избежать проблем с определением изменений. Это позволит dbt обнаруживать изменения, вместо сравнения текущего состояния с только что перезаписанной версией. -
Передайте флаг
--no-write-json:dbt ls --no-write-json --select state:modified --state targetна этапе воспроизведения.
Ложные срабатывания
Заключительное примечание
Сравнение состояний — сложная задача. Мы стремимся со временем обеспечить согласованность между всеми вариантами конфигурации, а также предоставить пользователям необходимый контроль, чтобы они могли надёжно возвращать все изменённые ресурсы — и только те, которые они ожидают. Если вам интересно узнать больше, ознакомьтесь с открытыми задачами с меткой "state" в репозитории dbt.
