Приём заказов: нужен ли слепку слой сырья #70

Closed
opened 2026-08-07 20:44:19 +03:00 by ddmitry · 1 comment
Owner

Part of #69.

Вопрос

Как заказы попадают из топика orders в хранилище: через слой сырья, как события, или сразу в ods.order_snapshot?

Развилку мастер-спека называет нерешённой прямо (раздел 7): «Как принимаются заказы — развилка этапа 3, и она не решена». Событиям выбран приём байтами с разбором функциями (ADR 0005); заказам тот же способ идёт только вместе с ответом, нужен ли им слой сырья вообще — у них слепок, а не поток.

Что стоит на кону: нужен — и получаем двух чтецов на один топик, схему, которую ADR 0005 отверг; не нужен — и слои перестают быть единообразными, а вместе с этим уходит место, где видно «какая нода читала топик».

Учебная сторона: сравнение двух способов приёма записано в опорные точки раздела 12 мастер-спеки.

Резолюция обязана лечь так, чтобы читалась рядом с ADR 0005 — новым ADR или дополнением к нему: иначе выбор для заказов окажется в другом жанре документа, чем выбор для событий, и сравнить их будет негде.

Part of #69. ## Вопрос Как заказы попадают из топика `orders` в хранилище: через слой сырья, как события, или сразу в `ods.order_snapshot`? Развилку мастер-спека называет нерешённой прямо (раздел 7): «Как принимаются заказы — развилка этапа 3, и она не решена». Событиям выбран приём байтами с разбором функциями ([ADR 0005](../adr/0005-event-ingestion.md)); заказам тот же способ идёт только вместе с ответом, нужен ли им слой сырья вообще — у них слепок, а не поток. Что стоит на кону: нужен — и получаем двух чтецов на один топик, схему, которую ADR 0005 отверг; не нужен — и слои перестают быть единообразными, а вместе с этим уходит место, где видно «какая нода читала топик». Учебная сторона: сравнение двух способов приёма записано в опорные точки раздела 12 мастер-спеки. Резолюция обязана лечь так, чтобы читалась рядом с ADR 0005 — новым ADR или дополнением к нему: иначе выбор для заказов окажется в другом жанре документа, чем выбор для событий, и сравнить их будет негде.
ddmitry added the wayfinder:grilling label 2026-08-07 20:44:19 +03:00
ddmitry added a new dependency 2026-08-07 20:44:43 +03:00
ddmitry self-assigned this 2026-08-12 20:04:43 +03:00
Author
Owner

Резолюция

Заказы принимаются пакетным забором: чтец топика байтовый (RawBLOB), как
у событий, но матвью к нему не привязана — сырьё забирает шаг, которым
управляет Airflow. Он вставляет прочитанное в stg.orders_raw, разбирает в
типизированный слепок и заменяет партицию дня в ods.order_snapshot. Тот же
даг проигрывает модельный день генератором, поэтому переливается ровно то, что
он положил в топик.

Слой сырья заказам нужен. Без него ods.order_snapshot повторил бы его
роль — «как приехало», без дедупа, — а обещание идемпотентности из раздела 2
мастер-спеки повисло бы ни на чём: матвью партиций не заменяет, и удвоение
слепка при повторной заливке жило бы вечно, потому что у ODS, в отличие от
сырья, срока жизни нет. При пакетном шаге каждый слой отрабатывает своё.

Топик ordersодна партиция, чтец — только на clickhouse-01, без
ON CLUSTER
: у пулла один тянущий по определению, а у Airflow одно
подключение, и оно к ноде 1.

Постановка тикета говорила про «двух чтецов на один топик» — этого выбора не
было ни в одной ветке: чтец на orders в любом случае один. Настоящая
развилка оказалась о другом — о режиме приёма, поток против слепка.

Решение целиком, с доводами и отвергнутыми вариантами (типизированный чтец
прямо в ODS, матвью из сырья как у событий, типизированный чтец при пулле,
Distributed поверх Kafka, две партиции, сенсор дневного батча) —
ADR 0008, docs/adr/0008-order-ingestion.md.

Что это поменяло за пределами тикета

  • Раздел 12 мастер-спеки переписан. Опорная точка «два способа принять
    топик» противопоставляла байтового чтеца типизированному — две формы одного
    приёма. Теперь она про поток против слепка, push против pull: чтец в обоих
    случаях байтовый, различает их режим. Пункт «Форма учебного сравнения двух
    способов приёма» уходит из «Ещё не сформулировано» карты — он решён, а не
    отложен.
  • Сенсор дневного батча снят (раздел 9). У топика нет сигнала «всё», и
    сенсор ловил бы момент, которого не существует; раз генератор и переливка в
    одном даге, ждать нечего по построению.
  • Этап 3 забирает у этапа 5 первый настоящий даг. Приём заказов без дага не
    существует. etl_pipeline остаётся за этапом 5.
  • Правки мастер-спеки: разделы 6, 7, 9, 11, 12. В CONTEXT.md заведены
    «слепок», «окно изменяемости», «пакетный забор».

Сверено по документации

MCP Context7, 12 августа 2026: прямое чтение из Kafka-движка запрещено с 21.12
и открывается stream_like_engine_allow_direct_select; при привязанной матвью
остаётся запрещённым — значит два способа приёма взаимоисключающи по
построению; офсеты прямое чтение по умолчанию не коммитит, нужна
kafka_commit_on_select; про Distributed поверх Kafka документация не
говорит ничего. Что осталось замерить на стенде — в конце ADR 0008.

## Резолюция Заказы принимаются **пакетным забором**: чтец топика байтовый (`RawBLOB`), как у событий, но матвью к нему не привязана — сырьё забирает шаг, которым управляет Airflow. Он вставляет прочитанное в `stg.orders_raw`, разбирает в типизированный слепок и заменяет партицию дня в `ods.order_snapshot`. Тот же даг проигрывает модельный день генератором, поэтому переливается ровно то, что он положил в топик. Слой сырья заказам **нужен**. Без него `ods.order_snapshot` повторил бы его роль — «как приехало», без дедупа, — а обещание идемпотентности из раздела 2 мастер-спеки повисло бы ни на чём: матвью партиций не заменяет, и удвоение слепка при повторной заливке жило бы вечно, потому что у ODS, в отличие от сырья, срока жизни нет. При пакетном шаге каждый слой отрабатывает своё. Топик `orders` — **одна партиция**, чтец — **только на `clickhouse-01`, без `ON CLUSTER`**: у пулла один тянущий по определению, а у Airflow одно подключение, и оно к ноде 1. Постановка тикета говорила про «двух чтецов на один топик» — этого выбора не было ни в одной ветке: чтец на `orders` в любом случае один. Настоящая развилка оказалась о другом — о режиме приёма, поток против слепка. Решение целиком, с доводами и отвергнутыми вариантами (типизированный чтец прямо в ODS, матвью из сырья как у событий, типизированный чтец при пулле, `Distributed` поверх Kafka, две партиции, сенсор дневного батча) — **[ADR 0008](https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/adr/0008-order-ingestion.md)**, `docs/adr/0008-order-ingestion.md`. ### Что это поменяло за пределами тикета - **Раздел 12 мастер-спеки переписан.** Опорная точка «два способа принять топик» противопоставляла байтового чтеца типизированному — две формы одного приёма. Теперь она про поток против слепка, push против pull: чтец в обоих случаях байтовый, различает их режим. Пункт «Форма учебного сравнения двух способов приёма» уходит из «Ещё не сформулировано» карты — он решён, а не отложен. - **Сенсор дневного батча снят** (раздел 9). У топика нет сигнала «всё», и сенсор ловил бы момент, которого не существует; раз генератор и переливка в одном даге, ждать нечего по построению. - **Этап 3 забирает у этапа 5 первый настоящий даг.** Приём заказов без дага не существует. `etl_pipeline` остаётся за этапом 5. - Правки мастер-спеки: разделы 6, 7, 9, 11, 12. В `CONTEXT.md` заведены «слепок», «окно изменяемости», «пакетный забор». ### Сверено по документации MCP Context7, 12 августа 2026: прямое чтение из Kafka-движка запрещено с 21.12 и открывается `stream_like_engine_allow_direct_select`; при привязанной матвью остаётся запрещённым — значит два способа приёма взаимоисключающи по построению; офсеты прямое чтение по умолчанию **не** коммитит, нужна `kafka_commit_on_select`; про `Distributed` поверх Kafka документация не говорит ничего. Что осталось замерить на стенде — в конце ADR 0008.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: ddmitry/clickstream-data-platform#70