Learning Platform
Глоссарий Troubleshooting
Урок 04.03 · 22 мин
Средний
microbatchdbt runbackfillparallel batchesretry

Запуск microbatch: обычный run, backfill, parallel, retry

В прошлых уроках мы видели концепт и конфигурацию microbatch. Сегодня — практика: как запускать microbatch в production. Разберём четыре сценария: обычный daily run, surgical backfill, parallel execution, retry after failure.

Обычный run

Самый простой случай — ежедневный/ежечасный run в Airflow или dbt Cloud:

dbt run --select fct_events

Что происходит:

  1. dbt находит max(event_time) в target.
  2. Вычисляет batches от max - lookback до now.
  3. Запускает каждый batch sequentially.
  4. Каждый batch — это DELETE+INSERT для своего time range.
  5. Batches коммитятся независимо. Если 3-й batch упал, 1-й и 2-й остаются в target.

Логи в dbt run:

Running with dbt=1.10.21
Found 1 model

12:00:01 Concurrency: 4 threads (target='dev')
12:00:01 1 of 1 START sql incremental model events.fct_events ............ [RUN]
12:00:02   Batch 1/4: 2026-05-16 00:00 - 2026-05-17 00:00 ...... [OK in 5.2s]
12:00:07   Batch 2/4: 2026-05-17 00:00 - 2026-05-18 00:00 ...... [OK in 4.8s]
12:00:11   Batch 3/4: 2026-05-18 00:00 - 2026-05-19 00:00 ...... [OK in 5.1s]
12:00:16   Batch 4/4: 2026-05-19 00:00 - 2026-05-20 00:00 ...... [OK in 3.9s]
12:00:20 1 of 1 OK created sql incremental model events.fct_events ...... [OK in 19s]

Это log одного microbatch run с 4 batches (3 lookback + 1 current). Каждый batch видно отдельно.

Selective backfill через —event-time-start/—event-time-end

Главная сила microbatch — surgical backfill через CLI флаги. Use case: исправили баг в логике, нужно пересчитать конкретный период.

# Пересчитать только апрель 2026:
dbt run \
    --select fct_events \
    --event-time-start='2026-04-01' \
    --event-time-end='2026-05-01'

dbt запустит batches только для дат внутри окна (30 days × batch_size=‘day’ = 30 batches).

Важные правила:

  1. --event-time-end exclusive. '2026-05-01' означает «до 1 мая, не включая 1 мая».
  2. Оба флага в формате ISO date (YYYY-MM-DD) или ISO timestamp (YYYY-MM-DDTHH:MM:SS).
  3. Без --event-time-end окно открытое — пересчитывается до now. Часто это не то, что хотите.
  4. Backfill не использует lookback — он пересчитывает ровно указанный диапазон.

Backfill scenarios

Scenario 1: Bug fix

# Нашли баг в case-statement, исправили, пересчитываем апрель:
dbt run --select fct_events --event-time-start='2026-04-01' --event-time-end='2026-05-01'

Scenario 2: Late-arriving data вне lookback

# Source за last week восстановили retroactively, lookback=3 не покрыл:
dbt run --select fct_events --event-time-start='2026-05-12' --event-time-end='2026-05-19'

Scenario 3: New downstream model нуждается в historical data

# Создаём новый dim_users, нужно пересчитать fct_events с самого начала:
dbt run --select fct_events --event-time-start='2024-01-01' --event-time-end='2026-05-19'

Scenario 4: Full refresh + selective

# Если хотите полный пересчёт, но через microbatch механизм (не --full-refresh):
dbt run --select fct_events --event-time-start='2024-01-01' --event-time-end='2026-05-19'

Технически это эквивалентно --full-refresh, но даёт visibility — видно progress per batch.

Parallel execution через —concurrent-batches

По умолчанию microbatch выполняет batches последовательно. Это безопасно, но медленно. На больших backfills (год+ данных) — часы compute.

--concurrent-batches параметр запускает batches параллельно:

# Запустить с 8 parallel batches:
dbt run \
    --select fct_events \
    --event-time-start='2024-01-01' \
    --event-time-end='2026-05-19' \
    --concurrent-batches=8

Что происходит:

  • dbt вычисляет все batches (~730 для 2 лет daily).
  • Запускает 8 одновременно через thread pool.
  • Когда один завершается, начинается следующий из очереди.
  • Все 730 обработаются за ~ (730 / 8) × avg_batch_time.

На warehouse с big compute (Snowflake LARGE, BigQuery slots) это 5-10x ускорение backfill.

Когда parallel опасен

--concurrent-batches работает не для всех models:

  1. Stateful logic — если модель зависит от ordering (например, running total per user), параллельные batches могут вычислять неправильно. Безопасно — explicit ORDER BY в SQL, чтобы каждый batch self-contained.

  2. Concurrent writes на DuckDB — single-writer per file. Local DuckDB упадёт при concurrent batches. На MotherDuck — OK.

  3. Race conditions на shared resources — если модель пишет в shared table или dependency, может быть corruption.

Правило: parallel батчи safe, если каждый batch self-contained — не зависит от предыдущих batches на уровне логики, не пишет в shared state.

Retry после failure

Это главное преимущество microbatch перед обычным incremental. Если один batch упал — не нужен полный —full-refresh.

Что происходит при failure

12:00:01 1 of 1 START sql incremental model events.fct_events ............ [RUN]
12:00:02   Batch 1/30: 2026-04-01 - 2026-04-02 ...... [OK in 5s]
12:00:07   Batch 2/30: 2026-04-02 - 2026-04-03 ...... [OK in 4s]
12:00:11   Batch 3/30: 2026-04-03 - 2026-04-04 ...... [OK in 5s]
12:00:16   Batch 4/30: 2026-04-04 - 2026-04-05 ...... [ERROR]
12:00:17 1 of 1 ERROR creating sql incremental model events.fct_events ....

Error: out of memory

После failure:

  • Batches 1-3 уже committed в target (DELETE+INSERT prior batch успешно).
  • Batch 4 НЕ committed — failure до COMMIT, target откатился к pre-batch state.
  • Batches 5-30 не запускались.

dbt retry

dbt retry

dbt смотрит в run_results.json предыдущего run, находит, что failure был на batch 4 модели fct_events, запускает только batches 4-30 (не 1-3, они OK).

Это критичный фичей для production:

  • Обычный incremental retry = весь run заново. На 4-часовом run после failure на 3-м часе — 4 часа заново.
  • Microbatch retry = только failed + downstream batches. На 30 batches retry batch 4 — 5 секунд.

Manual restart с конкретного batch

Если хотите явно указать starting point:

dbt run \
    --select fct_events \
    --event-time-start='2026-04-04' \
    --event-time-end='2026-05-01'

dbt запустит batches с 4 апреля. Useful когда dbt retry не доступен (changed config, etc.).

Run на dbt Cloud / Airflow

Airflow: backfill-safe DAGs — datetime.now и data_interval

В Airflow через dbt-airflow или dbt-cosmos:

from airflow import DAG
from cosmos import DbtTaskGroup, ProjectConfig, ProfileConfig

with DAG('daily_events_run', schedule='0 1 * * *') as dag:
    dbt_run = DbtTaskGroup(
        project_config=ProjectConfig('my_dbt_project'),
        profile_config=ProfileConfig(...),
        operator_args={
            'select': 'fct_events',
        }
    )

В dbt Cloud — обычный schedule job с командой dbt run --select fct_events.

Production gotchas

1. —event-time-end забыли

Без --event-time-end окно открытое. Backfill пересчитывает с start до сегодня. Часто это не то, что хотите. Всегда указывайте оба явно.

2. —concurrent-batches на shared resource

Запустили --concurrent-batches=16 на DuckDB locally — все batches пытаются писать в один .duckdb файл — кучи lock errors. Решение — sequential на local DuckDB, parallel только на MotherDuck/Snowflake/BQ.

3. dbt retry после рестарта Airflow

Если Airflow рестартовал между runs, run_results.json может потеряться (особенно с in-memory backends). dbt retry не найдёт state. Решение — persistent storage для run_results.json (S3, GCS).

4. Конкурентные runs от разных jobs

Два Airflow задач одновременно запускают dbt run --select fct_events — оба видят свои batches как pending, оба запускают, конфликт на target. Решение — concurrency lock в Airflow на уровне задачи.

5. CET vs UTC mismatch

--event-time-start='2026-04-01' — dbt интерпретирует как UTC midnight. Если ваш timezone CET (UTC+1), вы можете ожидать 00:00 CET, а получите 01:00 CET. На границе months — потеря 1 часа данных. Всегда работайте в UTC.

Real production schedule

Типичный production schedule для microbatch event-table:

# Airflow DAG
schedule: '0 */4 * * *'  # каждые 4 часа

tasks:
  - name: refresh_events
    operator: BashOperator
    bash_command: 'dbt run --select fct_events --target prod'

Каждые 4 часа dbt запускает microbatch. Lookback=3 пересчитывает последние 3 days. Если что-то падает — dbt retry через manual trigger в Airflow UI.

Параллельно еженедельный full-week-backfill для catch-up late-arrivals за пределами lookback:

schedule: '0 2 * * 0'  # Sunday 2am

tasks:
  - name: weekly_backfill
    operator: BashOperator
    bash_command: |
      dbt run --select fct_events \
        --event-time-start="{{ ds_add(ds, -14) }}" \
        --event-time-end="{{ ds }}" \
        --target prod

Это паттерн 3-tier: regular (every 4h), recovery (manual via retry), catch-all (weekly).

DuckDB-специфика

  • --concurrent-batches на local DuckDB — не использовать, single-writer.
  • --concurrent-batches=4 на MotherDuck — OK, но мониторьте memory_limit.
  • dbt retry работает идентично Snowflake/BQ.
  • --event-time-start/--event-time-end — поддерживается с dbt-duckdb 1.10+.

Попробуй сам

В своём проекте на microbatch модели:

  1. Запустите обычный dbt run. Посмотрите log — сколько batches?
  2. Сделайте selective backfill: --event-time-start='X' --event-time-end='Y'. Засеките время.
  3. Сравните с --full-refresh. Microbatch backfill должен быть быстрее на большом окне (благодаря per-batch retry potential).
  4. Симулируйте failure: добавьте assert(false) в SQL для одного batch (через case). Запустите run, увидите failure посередине. Запустите dbt retry — увидите, что предыдущие batches не пересчитываются.
  5. (Опционально) Запустите с --concurrent-batches=4 (только на NOT-local DuckDB) — увидите speedup.
Проверка знанийKnowledge check
Команда замечает: microbatch модель fct_events не каждый run обрабатывает одинаковое количество batches. Иногда 4, иногда 7, иногда 1. С чем это связано?
ОтветAnswer
Это нормальное поведение microbatch, объясняемое тем, что dbt динамически вычисляет batches на основе двух факторов: max(event_time) в target и now. Конкретные сценарии. (1) Регулярный 4-часовой schedule, обычно 1 batch (текущий day) + lookback batches (3 days назад). Итого 4 batches. (2) Если предыдущий run failed на 5-м batch из 8, dbt retry или следующий regular run видит, что 5-8 ещё не обработаны, и запускает их + lookback. Это может быть 7 batches. (3) Если был downtime Airflow на сутки, max(event_time) в target вчерашний, а now сегодняшний — нужно обработать сегодняшние batches + lookback. Это может быть 4-5 batches. (4) Если запустили 'dbt run --event-time-start --event-time-end' для backfill, microbatch обрабатывает ровно указанный диапазон — 1-30 batches. (5) Если был --full-refresh — microbatch перезапускает с begin до сегодня (730 batches при 2 годах daily). Это всё expected behavior. Если хотите больше предсказуемости — мониторить через dbt run --output json и парсить количество batches per run для anomaly detection. Резкий скачок 'обычно 4, вдруг 50' — сигнал что что-то не так (Airflow downtime, dbt state потеряно, кто-то запустил manual backfill). Главное — понимать, что microbatch reactive: реагирует на состояние target и now. Это feature, не bug.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 6. Что делает 'dbt run --select my_model --event-time-start=2026-04-01 --event-time-end=2026-05-01'?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4