- Зачем:
- справочники читает человек со стороны, а «пульт мира», «опись мира»,
«работник» и «сырьё» звучали шуткой или калькой времён разработки
(тикет #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
68 lines
3.3 KiB
Python
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()
|