Files
clickstream-data-platform/dags/orders_ingest.py
T
ddadminandClaude Fable 5.1 59d8c83b17 docs(glossary): четыре термина переименованы, world.md и stand.md вычитаны
- Зачем:
  - справочники читает человек со стороны, а «пульт мира», «опись мира»,
    «работник» и «сырьё» звучали шуткой или калькой времён разработки
    (тикет #214, выбор владельца).
- Что:
  - CONTEXT.md: статьи «Паспорт мира», «Даги модельного времени»,
    «Шаговый даг», «Сырые данные», старые слова в строках «Избегать»;
    пометки в ADR 0005, 0008, 0009 без переписывания решений.
  - замены по README, справочникам, путеводителю, лабам, спекам,
    комментариям дагов и SQL, тегу дага и панели Grafana; имена в коде
    не тронуты.
  - world.md и stand.md: 35 находок вычитки внесены, регистр выровнен.
- Проверка:
  - make config-test; make lint в корне и в generator/; make test в
    generator/ (437 passed); скрипт ссылок из #212 пуст; grep старых
    слов вне ADR, research и CONTEXT.md пуст.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QBCtU38qSHg5DvgtnKXcW
2026-09-02 16:46:50 +03:00

68 lines
3.3 KiB
Python

"""Приём заказов: пакетный забор слепка из Kafka в хранилище.
Путь Kafka → STG → ODS у заказов один и живёт одним дагом: сначала забор
порции в `stg`, затем разбор того же среза в типизированный ODS и в таблицу
брака. Расписания у дага нет: его дёргает тот, кто положил слепок в топик, —
шаговый даг модельного времени после проигрыша дня, — и ждёт конца.
Контраст с приёмом событий и есть урок. События тянет матвью, навсегда
подписанная на чтеца: приём идёт сам, пока идёт поток. Слепок заказов
приезжает раз в модельный день целой выгрузкой, у которой есть начало и конец,
и забирает её запрос по команде. Push против pull — два режима на одном стенде,
каждый там, где ему место по природе источника.
Решения и доводы целиком — ADR 0008 (забор) и ADR 0010 (версии в ODS); форма
перехода — docs/architecture/orders/ingestion.md.
"""
from __future__ import annotations
import datetime
from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
from airflow.sdk import dag
START_DATE = datetime.datetime(2026, 1, 1, tzinfo=datetime.UTC)
# Запросы лежат файлами в sql/ репозитория, разложенные по слоям хранилища;
# сюда их монтирует compose — всем службам Airflow сразу.
SQL_ROOT = "/opt/airflow/sql"
@dag(
dag_id="orders_ingest",
schedule=None,
start_date=START_DATE,
is_paused_upon_creation=False,
# Чтец у топика один, и группа потребителей у него одна. Два прогона разом
# дрались бы за неё, а слепок разъехался бы по двум _load_id; второй
# прогон подождёт своей очереди.
max_active_runs=1,
template_searchpath=SQL_ROOT,
tags=["заказы"],
)
def orders_ingest():
"""Забрать приехавший слепок заказов и разложить его по слоям."""
pull_batch = SQLExecuteQueryOperator(
task_id="pull_batch",
conn_id="clickhouse_default",
sql="stg/orders_raw_load.sql",
parameters={"load_id": "{{ run_id }}"},
do_xcom_push=False,
)
parse_batch = SQLExecuteQueryOperator(
task_id="parse_batch",
conn_id="clickhouse_default",
sql="ods/order_parse.sql",
parameters={"load_id": "{{ run_id }}"},
split_statements=True,
do_xcom_push=False,
)
# ClickHouse не даёт транзакции между двумя вставками parse_batch. Один
# task_id сохраняет их порядок и одну точку повтора для неизменного load_id.
pull_batch >> parse_batch
orders_ingest()