# lag\_tolerance

### YAML-файл проекта

dbt\_project.yml

```yaml
models:
  <resource-path>:
    +state:
      lag_tolerance: <duration_string>
```

### YAML-файл свойств

models/\<filename>.yml

```yaml
models:
  - name: my_model
    config:
      state:
        lag_tolerance: <duration_string>
```

### Конфигурация в SQL-файле

models/\<filename>.sql

```sql
{{ config(
    state={
      "lag_tolerance": "<duration_string>"
    }
) }}
```

## Определение

Исходные системы могут обновляться чаще, чем требуется пересобирать некоторые нижестоящие модели. Например, модель для ежедневной отчётности не нужно обновлять чаще одного раза в день, даже если новые вышестоящие данные поступают каждый час, тогда как модель для расчёта метрик, доступных клиентам, использующая часть тех же источников, может требовать обновления каждые 30 минут.

`lag_tolerance` задаёт время, которое dbt State выжидает перед пересборкой узла при изменении вышестоящих данных. Узел пересобирается, только когда выполняются *оба* условия: с момента его последней сборки прошло больше времени, чем задано в `lag_tolerance`, и вышестоящие данные изменились с момента этой сборки. Это создаёт буфер, позволяющий экономить вычислительные ресурсы и соблюдать [соглашения об уровне обслуживания (SLA)](https://www.getdbt.com/blog/data-slas-best-practices) в отношении актуальности данных без ненужных пересборок. Поддерживаются два основных сценария:

* **Согласование сборок с требованиями SLA**: `lag_tolerance` позволяет напрямую согласовать выполнение моделей с требованиями SLA к актуальности данных, отделяя частые изменения вышестоящих данных от нижестоящих моделей с менее строгими требованиями к актуальности.
* **Экономия вычислительных ресурсов при нарушениях SLA вышестоящих зависимостей**: `lag_tolerance` защищает ваш бюджет на вычисления при нарушениях SLA по актуальности, предотвращая затратные пересборки нижестоящих моделей на неизменившихся данных, когда вышестоящая зависимость не соответствует своему SLA по актуальности.

Конфигурация `lag_tolerance` принимает два типа значений:

* **Строки длительности** в формате `<number><unit>`:

  | Единица измерения | Допустимые значения      |
  | ----------------- | ------------------------ |
  | Секунды           | `s`, `second`, `seconds` |
  | Минуты            | `m`, `minute`, `minutes` |
  | Часы              | `h`, `hour`, `hours`     |
  | Дни               | `d`, `day`, `days`       |
  | Недели            | `w`, `week`, `weeks`     |

* **Выражения Jinja** — `lag_tolerance` вычисляется как шаблон Jinja, поэтому для динамического задания допустимых задержек можно использовать любые переменные контекста dbt (`target`, `var()`, `env_var()`). Это удобно для задания разных допустимых задержек в разных окружениях без дублирования блоков конфигурации:

  ```yaml
  lag_tolerance: "{{ '4h' if target.name == 'prod' else '7d' }}"
  ```

### Когда узел пересобирается

dbt State пересобирает узел, только когда выполняются *оба* условия. Если хотя бы одно из них не выполняется, используется существующий узел:

| Условие                       | Что оно означает                                                                         |
| ----------------------------- | ---------------------------------------------------------------------------------------- |
| Допустимая задержка истекла   | С момента последней сборки узла прошло больше времени, чем задано в его `lag_tolerance`. |
| Вышестоящие данные изменились | Хотя бы в одной вышестоящей зависимости появились новые данные с момента этой сборки.    |

`lag_tolerance` задаёт минимальный интервал между пересборками

`lag_tolerance` определяет, как часто узел может пересобираться, а не то, насколько актуальными должны быть его вышестоящие данные.

#### Пример

Допустим, у вас есть задание, которое запускается каждые 30 минут, для модели задана допустимая задержка `45m`, а последняя сборка состоялась в `08:00`. Новые вышестоящие данные поступили в `08:20`.

| Запуск задания | Время с последней сборки | Есть новые вышестоящие данные с момента последней сборки? | Результат                                                                                        |
| -------------- | ------------------------ | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `08:30`        | `30m`                    | Да                                                        | Повторное использование: допустимая задержка ещё не истекла.                                     |
| `09:00`        | `60m`                    | Да                                                        | Пересборка: оба условия выполнены.                                                               |
| `09:30`        | `30m`                    | Нет                                                       | Повторное использование: допустимая задержка ещё не истекла, а вышестоящие данные не изменились. |
| `10:00`        | `60m`                    | Нет                                                       | Повторное использование: вышестоящие данные не изменились с `09:00`.                             |

Данные, поступившие в `08:20`, ожидали обработки до `09:00`. Это был первый запуск, при котором с момента сборки прошло больше `45m` *и* вышестоящие данные изменились. В `10:00` с момента сборки прошло достаточно времени, но, поскольку после `09:00` новые вышестоящие данные не поступали, dbt повторно использовал узел.

Чтобы пересобирать узел при каждом изменении его вышестоящих данных, установите `lag_tolerance` в `0s`:

```yaml
state:
  lag_tolerance: 0s
```

### Когда применяется `lag_tolerance`

`lag_tolerance` применяется только к проверкам актуальности данных. Нижестоящая модель всё равно пересобирается до истечения допустимой задержки, если скомпилированный SQL вышестоящей модели изменился с момента последнего запуска, независимо от настройки `lag_tolerance`.

Это часто происходит с инкрементальными моделями. При первом запуске инкрементальная модель выполняет полную загрузку без предложения `WHERE`. При последующих запусках `is_incremental()` возвращает true и добавляется фильтр, что изменяет скомпилированный SQL. dbt State определяет это как изменение запроса вышестоящей модели и пересобирает все нижестоящие модели, даже те, для которых `lag_tolerance` ещё не истёк.

Например, `fct_orders` — инкрементальная модель, от которой зависит `agg_orders_daily`:

models/fct\_orders.sql

```sql
{{ config(materialized='incremental', unique_key='id') }}

select id, amount from {{ ref('raw_orders') }}
{% if is_incremental() %}
where id > (select max(id) from {{ this }})
{% endif %}
```

models/agg\_orders\_daily.sql

```sql
{{ config(materialized='table', state={'lag_tolerance': '3h'}) }}

select date_trunc('day', created_at) as day, sum(amount) as total
from {{ ref('fct_orders') }}
group by 1
```

Когда `fct_orders` переходит от полной загрузки к инкрементальному запуску, её скомпилированный SQL меняется. При этом запуске `agg_orders_daily` пересобирается, несмотря на заданный для неё `lag_tolerance` в 3 часа.

подсказка

Чтобы помочь вам настроить значения `lag_tolerance`, страница **dbt State** на dbt platform предоставляет [рекомендации по допустимому отставанию](https://docs.getdbt.tech/docs/deploy/dbt-state-interface.md#lag-tolerance-recommendations) на основе истории сборок ваших моделей за последние 30 дней, позволяя определить, для каких моделей будет полезно увеличить допустимое отставание.

## Значение по умолчанию

Если вы не задаёте `lag_tolerance`, dbt State использует `45m` (45 минут).

## Примеры

### Использование разных допустимых задержек в разных окружениях

Используйте выражение Jinja, чтобы задать меньшую допустимую задержку в промышленном окружении и большую — в остальных. Это позволяет поддерживать актуальность данных в промышленном окружении и сокращать ненужные пересборки при разработке:

dbt\_project.yml

```yaml
models:
  +state:
    lag_tolerance: "{{ '4h' if target.name == 'prod' else '7d' }}"
```

В этом примере модели для целевого окружения `prod` пересобираются, когда с момента последней сборки прошло больше 4 часов и вышестоящие данные изменились. Во всех остальных окружениях модели пересобираются, когда с момента последней сборки прошло больше 7 дней и вышестоящие данные изменились.

### Изменение допустимой задержки в зависимости от дня недели

Используйте выражение Jinja, чтобы определить день недели и задать более строгую допустимую задержку в будни, чем в выходные:

dbt\_project.yml

```yaml
models:
  +state:
    lag_tolerance: "{{ '24h' if modules.datetime.datetime.today().weekday() in (5, 6) else '1h' }}"
```

В этом примере модели пересобираются, когда с момента последней сборки прошло больше 1 часа (с понедельника по пятницу) или больше 24 часов (с субботы по воскресенье) и вышестоящие данные изменились.

### Применение разных допустимых задержек к разным папкам

Задайте разные допустимые задержки для разных частей проекта, указав соответствующие папки:

dbt\_project.yml

```yaml
models:
  <your_project>:
    marts:
      +state:
        lag_tolerance: 1d
    staging:
      +state:
        lag_tolerance: 1h
```

### Переопределение для отдельной модели

Переопределите значение по умолчанию, заданное на уровне проекта, для отдельной модели:

models/my\_model.yml

```yaml
models:
  - name: my_model
    config:
      state:
        lag_tolerance: 1h
```

## Связанная документация

* [О dbt State](https://docs.getdbt.tech/docs/deploy/dbt-state-about.md)
* [Настройка dbt State](https://docs.getdbt.tech/docs/deploy/dbt-state-setup.md)
* [Мониторинг активности dbt State](https://docs.getdbt.tech/docs/deploy/dbt-state-interface.md)
