Ночной ETL: извлечение, преобразование и загрузка шагами пайплайна без Airflow
Типичный ночной контур — три шага одного пайплайна по расписанию cron: извлечение данных из источников (extract), их очистка и агрегация (transform), запись в целевое хранилище для отчётности (load). У каждого шага в пайплайне могут быть свои повторы при сбое: если падает загрузка, не нужно заново вытягивать тяжёлое извлечение из внешних систем. Для контура из нескольких шагов отдельный кластер оркестратора и свой планировщик часто дают лишнюю сложность без выигрыша в надёжности.
Обновлено: 2026-04-20
Кратко
Суть ответа
Ночной ETL: извлечение, преобразование и загрузка шагами пайплайна без Airflow. Извлечение, преобразование и загрузку оформляют как отдельные функции или шаги с явным порядком выполнения. Тогда сбой на загрузке можно повторить точечно, не передёргивая тяжёлое извлечение из источников.
Когда подходит и когда нет
- Контур до примерно десяти последовательных шагов без сложных циклов и динамически собираемого графа задач
- Нужны повторы отдельных шагов при сбое без развёртывания отдельного оркестратора вроде Airflow
На что обратить внимание
- Один длинный cron-скрипт без разделения на шаги: при частичном сбое непонятно, на каком этапе остановились и можно ли безопасно продолжить — состояние данных «ни да ни нет».
- Если загрузка в витрину не идемпотентна, повтор прогона после сбоя или ручной перезапуск дублируют строки в аналитической таблице.
Ситуация: нагрузка и где обычно ломается
Почему ночной ETL без встроенных пайплайнов быстро усложняется
- Airflow: powerful DAG orchestration, but a Kubernetes cluster or managed cloud service to maintain
- Prefect / Dagster: better developer experience than Airflow, but still requires a separate deployment
- crontab: simple but no run history, no retries, no dependency tracking between steps
- Lambda + EventBridge: possible, but step chaining and observability require significant wiring
Airflow, Luigi, Prefect и аналоги оправданы при больших графах задач и сложных зависимостях. Если же у вас ночной цикл из трёх–пяти понятных шагов, заводить под него отдельный кластер оркестратора, отдельный деплой и отдельную систему мониторинга часто невыгодно: растёт операционная нагрузка, а не качество данных.
Когда упрощённых рецептов мало
Где ломаются «простые» сценарии ETL
Один длинный cron-скрипт без разделения на шаги: при частичном сбое непонятно, на каком этапе остановились и можно ли безопасно продолжить — состояние данных «ни да ни нет».
Если загрузка в витрину не идемпотентна, повтор прогона после сбоя или ручной перезапуск дублируют строки в аналитической таблице.
Как Inquir помогает в этом сценарии
Ночной ETL как цепочка шагов пайплайна
Извлечение, преобразование и загрузку оформляют как отдельные функции или шаги с явным порядком выполнения. Тогда сбой на загрузке можно повторить точечно, не передёргивая тяжёлое извлечение из источников.
В консоли видно историю прогонов: какой шаг завершился с ошибкой, сколько строк прошло через каждый этап, когда состоялся следующий запуск по расписанию.
Что вы получаете на платформе
Что нужно для устойчивого ночного ETL
Изоляция шагов и точечные повторы
Извлечение, преобразование и загрузка — отдельные шаги пайплайна; при сбое платформа может повторить только упавший шаг, а не весь контур.
Идемпотентная загрузка
Стратегия «очистить партицию и вставить заново», MERGE или UPSERT по ключу — чтобы повторный прогон давал тот же итог в целевой таблице, что и первый успешный.
История прогонов
Каждый запуск по cron фиксируется с журналами по шагам: сколько строк извлечено, преобразовано и загружено.
Зависимости между шагами
Преобразование стартует только после успешного извлечения; загрузка — только после успешного преобразования (или после записи промежуточного результата в надёжное хранилище).
Что сделать дальше, по шагам
Как организовать ночной ETL-пайплайн
Извлечение (extract)
Запросить данные из источников (база, HTTP API, файлы) за нужный интервал — например, за прошедшие сутки.
Преобразование (transform)
Агрегация, очистка, обогащение справочниками. Результат удобно сохранить во временную таблицу или объект в хранилище.
Загрузка (load)
Идемпотентная запись в аналитическое хранилище: например, очистка партиции и вставка, MERGE или UPSERT по бизнес-ключу.
Пример кода
Nightly ETL: API → transform → Postgres
Cron triggers nightly at 02:00 UTC. Extract step fetches, transform step normalizes, load step upserts. Each step retries independently.
export async function handler(event) { const date = new Date().toISOString().slice(0, 10); // YYYY-MM-DD const records = await externalApi.fetchDailyReport(date); // Store to object storage — pipeline passes storage key to next step const key = `etl/raw/${date}.json`; await storage.putJson(key, records); return { key, count: records.length, date }; }
export async function handler(event) { const { key, date } = event.previousOutput ?? {}; const raw = await storage.getJson(key); const transformed = raw.map((r) => ({ id: r.external_id, date, revenue: parseFloat(r.revenue_usd), region: r.region?.toLowerCase(), updatedAt: new Date().toISOString(), })); const outKey = `etl/transformed/${date}.json`; await storage.putJson(outKey, transformed); return { outKey, count: transformed.length, date }; }
Когда подходит и когда нет
Когда Inquir уместен для ETL
Когда это уместно
- Контур до примерно десяти последовательных шагов без сложных циклов и динамически собираемого графа задач
- Нужны повторы отдельных шагов при сбое без развёртывания отдельного оркестратора вроде Airflow
Когда лучше не трогать
- Десятки взаимозависимых задач, динамический DAG, строгие SLA оркестрации — здесь специализированные системы (Airflow, Prefect и др.) обычно гибче
Вопросы и ответы
Вопросы и ответы
Как передать данные между шагами?
Обычно через объектное хранилище (ключ объекта передают в полезной нагрузке следующего шага) или через промежуточную таблицу в базе, если объём позволяет.
Можно ли параллельно извлекать из нескольких источников?
Да: несколько шагов без явной зависимости `dependsOn` могут выполняться параллельно — например, одновременное чтение из разных API или баз.