Перейти к основному содержимому

Клонирование инкрементальных моделей как первый шаг вашей CI задачи

Прежде чем начать, вы должны знать о нескольких условиях:

  • dbt clone доступен только в dbt версии 1.6 и новее. Обратитесь к нашему руководству по обновлению для помощи в активации новых версий в dbt Cloud.
  • Эта стратегия работает только для хранилищ, поддерживающих клонирование без копирования (в противном случае dbt clone просто создаст указательные представления).
  • Некоторые команды могут захотеть протестировать, что их инкрементальные модели работают как в инкрементальном режиме, так и в режиме полного обновления.

Представьте, что вы создали Slim CI задачу в dbt Cloud, и она настроена на:

  • Откладывание на ваше производственное окружение.
  • Выполнение команды dbt build --select state:modified+ для выполнения и тестирования всех моделей, которые вы изменили, и их зависимостей.
  • Запуск при открытии разработчиком вашей команды PR против основной ветки.
Пример slim CI задачи с вышеуказанными настройкамиПример slim CI задачи с вышеуказанными настройками

Теперь представьте, что ваш dbt проект выглядит примерно так в DAG:

Пример DAG проектаПример DAG проекта

Когда вы открываете pull request (PR), который изменяет dim_wizards, ваша CI задача начнется и построит только измененные модели и их зависимости (в данном случае, dim_wizards и fct_orders) в временной схеме, уникальной для вашего PR.

Это построение имитирует поведение, которое произойдет после слияния PR в основную ветку. Это гарантирует, что вы не вносите критических изменений, не требуя построения всего вашего dbt проекта.

Что происходит, когда одна из измененных моделей (или одна из их зависимостей) является инкрементальной моделью?

Поскольку ваша CI задача строит измененные модели в схеме, специфичной для PR, при первом выполнении dbt build --select state:modified+, измененная инкрементальная модель будет построена полностью, потому что она еще не существует в схеме, специфичной для PR, и is_incremental будет ложным. Вы работаете в режиме full-refresh.

Это может быть не оптимально, потому что:

  • Обычно инкрементальные модели являются вашими крупнейшими наборами данных, поэтому их полное построение занимает много времени, что может замедлить время разработки и привести к высоким затратам на хранилище.
  • Существуют ситуации, когда full-refresh инкрементальной модели успешно проходит в вашей CI задаче, но инкрементальное построение той же таблицы в продакшене может завершиться неудачей при слиянии PR в основную ветку (например, дрейф схемы, когда конфигурация on_schema_change установлена на fail).

Вы можете смягчить эти проблемы, клонируя без копирования соответствующие, уже существующие инкрементальные модели в схему, специфичную для PR, как первый шаг CI задачи, используя команду dbt clone. Таким образом, инкрементальные модели уже существуют в схеме, специфичной для PR, когда вы впервые выполняете команду dbt build --select state:modified+, и флаг is_incremental будет true.

У вас будет две команды для выполнения проверки CI в dbt Cloud:

  1. Клонируйте все уже существующие инкрементальные модели, которые были изменены или являются зависимыми от другой измененной модели:
dbt clone --select state:modified+,config.materialized:incremental,state:old
  1. Постройте все модели, которые были изменены, и их зависимости:
dbt build --select state:modified+

Благодаря вашему первому шагу клонирования, инкрементальные модели, выбранные в вашем dbt build на втором шаге, будут выполняться в инкрементальном режиме.

Команда клонирования в конфигурации CIКоманда клонирования в конфигурации CI

Ваши CI задачи будут выполняться быстрее, и вы более точно имитируете поведение, которое произойдет после слияния PR в основную ветку.

Расширение на тему "думайте о дрейфе схемы", когда конфигурация on_schema_change установлена на fail

Представьте, что у вас есть инкрементальная модель my_incremental_model с следующей конфигурацией:


{{
config(
materialized='incremental',
unique_key='unique_id',
on_schema_change='fail'
)
}}

Теперь, допустим, вы открываете PR, который добавляет новый столбец в my_incremental_model. В этом случае:

  • Инкрементальное построение завершится неудачей.
  • full-refresh будет успешным.

Если у вас есть ежедневная производственная задача, которая просто выполняет dbt build без флага --full-refresh, после слияния PR в основную ветку и запуска задачи, вы получите ошибку. Итак, вопрос - что вы хотите, чтобы произошло в CI?

  • Хотите ли вы также получить ошибку в CI, чтобы знать, что после слияния этого PR в основную ветку вам нужно немедленно выполнить dbt build --full-refresh --select my_incremental_model в продакшене, чтобы избежать ошибки в продакшене? Это заблокирует прохождение вашей проверки CI.
  • Хотите ли вы, чтобы ваша проверка CI прошла успешно, потому что после выполнения full-refresh для этой модели в продакшене вы будете в успешном состоянии? Это может привести к неприятным сюрпризам, если ваша производственная задача внезапно начнет давать сбой при слиянии этого PR в основную ветку, если вы не помните, что вам нужно выполнить dbt build --full-refresh --select my_incremental_model в продакшене.

Здесь, вероятно, нет идеального решения; это все просто компромиссы! Наше предпочтение - иметь неудачную CI задачу и вручную переопределить блокирующее правило защиты ветки, чтобы не было сюрпризов, и мы могли проактивно выполнить соответствующую команду в продакшене после слияния PR.

Расширение на тему "почему state:old"

Для совершенно новых инкрементальных моделей вы хотите, чтобы они выполнялись в режиме full-refresh в CI, потому что они будут выполняться в режиме full-refresh в продакшене, когда PR будет слит в main. Они также еще не существуют в производственной среде... они совершенно новые! Если вы не укажете это, вы не получите ошибку, просто “No relation found in state manifest for…”. Таким образом, технически это работает без указания state:old, но добавление state:old более явно и означает, что он даже не попытается клонировать совершенно новые инкрементальные модели.

0