From 31dde678c52c911cbed077991a38daa999a3ba64 Mon Sep 17 00:00:00 2001 From: Dmitry Dementev Date: Sun, 18 Jan 2026 21:56:17 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0?= =?UTF-8?q?=D1=80=D0=B8=D0=B5=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/internal/bookings_stg_code_review.md | 5 +++-- sql/stg/airplanes_load.sql | 2 +- sql/stg/airports_load.sql | 2 +- sql/stg/boarding_passes_load.sql | 3 ++- sql/stg/bookings_load.sql | 1 + sql/stg/flights_load.sql | 1 + sql/stg/routes_load.sql | 3 ++- sql/stg/seats_load.sql | 3 ++- sql/stg/segments_load.sql | 3 ++- sql/stg/tickets_load.sql | 2 +- 10 files changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/internal/bookings_stg_code_review.md b/docs/internal/bookings_stg_code_review.md index 0eef27e..ba261c0 100644 --- a/docs/internal/bookings_stg_code_review.md +++ b/docs/internal/bookings_stg_code_review.md @@ -89,7 +89,7 @@ - Для snapshot-справочников (`airports`, `airplanes`, `routes`, `seats`) пустой источник считаем ошибкой: это почти всегда признак проблем с PXF/источником. -### 3.2. Комментарии в `*_load.sql`: точнее формулировать “идемпотентность”, а не “дедупликацию источника” +### 3.2. Комментарии в `*_load.sql`: точнее формулировать “идемпотентность”, а не “дедупликацию источника” (статус: исправлено) Типовой паттерн: ```sql @@ -101,7 +101,8 @@ WHERE NOT EXISTS ( Это в первую очередь защита от повторного запуска того же таска в рамках одного `batch_id` (retry), а не “лечение” дублей в источнике. -Рекомендация: заменить формулировку комментариев на “идемпотентность для текущего батча”. +Что сделано: +- В `sql/stg/*_load.sql` комментарии приведены к формулировке “идемпотентность при повторном запуске/ретрае”. ### 3.3. Проверка составных ключей: избегать склейки строк diff --git a/sql/stg/airplanes_load.sql b/sql/stg/airplanes_load.sql index b140add..49d7157 100644 --- a/sql/stg/airplanes_load.sql +++ b/sql/stg/airplanes_load.sql @@ -20,7 +20,7 @@ SELECT '{{ run_id }}'::text FROM stg.airplanes_ext AS ext WHERE NOT EXISTS ( - -- Защита от дублей в рамках одного batch_id + -- Идемпотентность: при повторном запуске/ретрае не вставляем повторно те же строки в рамках текущего batch_id. SELECT 1 FROM stg.airplanes AS a WHERE a.batch_id = '{{ run_id }}'::text diff --git a/sql/stg/airports_load.sql b/sql/stg/airports_load.sql index 3197c2d..a3bb1a1 100644 --- a/sql/stg/airports_load.sql +++ b/sql/stg/airports_load.sql @@ -24,7 +24,7 @@ SELECT '{{ run_id }}'::text FROM stg.airports_ext AS ext WHERE NOT EXISTS ( - -- Защита от дублей в рамках одного batch_id + -- Идемпотентность: при повторном запуске/ретрае не вставляем повторно те же строки в рамках текущего batch_id. SELECT 1 FROM stg.airports AS a WHERE a.batch_id = '{{ run_id }}'::text diff --git a/sql/stg/boarding_passes_load.sql b/sql/stg/boarding_passes_load.sql index 1d94b7d..00899db 100644 --- a/sql/stg/boarding_passes_load.sql +++ b/sql/stg/boarding_passes_load.sql @@ -23,7 +23,8 @@ SELECT '{{ run_id }}'::text FROM stg.boarding_passes_ext AS ext WHERE NOT EXISTS ( - -- Защита от дублей в рамках одного batch_id + -- Идемпотентность: при повторном запуске/ретрае не вставляем повторно те же строки в рамках текущего batch_id. + -- Считаем ключом строки (ticket_no, flight_id). SELECT 1 FROM stg.boarding_passes AS bp WHERE bp.batch_id = '{{ run_id }}'::text diff --git a/sql/stg/bookings_load.sql b/sql/stg/bookings_load.sql index 522c0fc..6c336a4 100644 --- a/sql/stg/bookings_load.sql +++ b/sql/stg/bookings_load.sql @@ -29,6 +29,7 @@ FROM stg.bookings_ext AS ext CROSS JOIN max_batch_ts AS mb WHERE ext.book_date > mb.max_ts AND NOT EXISTS ( + -- Идемпотентность: при повторном запуске/ретрае не вставляем повторно те же строки в рамках текущего batch_id. SELECT 1 FROM stg.bookings AS b WHERE b.batch_id = '{{ run_id }}'::text diff --git a/sql/stg/flights_load.sql b/sql/stg/flights_load.sql index 5a6188e..e7879dd 100644 --- a/sql/stg/flights_load.sql +++ b/sql/stg/flights_load.sql @@ -37,6 +37,7 @@ FROM stg.flights_ext AS ext CROSS JOIN max_batch_ts AS mb WHERE ext.scheduled_departure > mb.max_ts AND NOT EXISTS ( + -- Идемпотентность: при повторном запуске/ретрае не вставляем повторно те же строки в рамках текущего batch_id. SELECT 1 FROM stg.flights AS f WHERE f.batch_id = '{{ run_id }}'::text diff --git a/sql/stg/routes_load.sql b/sql/stg/routes_load.sql index 77c2077..1bb76a1 100644 --- a/sql/stg/routes_load.sql +++ b/sql/stg/routes_load.sql @@ -28,7 +28,8 @@ SELECT '{{ run_id }}'::text FROM stg.routes_ext AS ext WHERE NOT EXISTS ( - -- Защита от дублей в рамках одного batch_id по составному ключу (route_no, validity) + -- Идемпотентность: при повторном запуске/ретрае не вставляем повторно те же строки в рамках текущего batch_id. + -- Считаем ключом строки (route_no, validity). SELECT 1 FROM stg.routes AS r WHERE r.batch_id = '{{ run_id }}'::text diff --git a/sql/stg/seats_load.sql b/sql/stg/seats_load.sql index 3c530d0..2e9720b 100644 --- a/sql/stg/seats_load.sql +++ b/sql/stg/seats_load.sql @@ -18,7 +18,8 @@ SELECT '{{ run_id }}'::text FROM stg.seats_ext AS ext WHERE NOT EXISTS ( - -- Защита от дублей в рамках одного batch_id по составному ключу (airplane_code, seat_no) + -- Идемпотентность: при повторном запуске/ретрае не вставляем повторно те же строки в рамках текущего batch_id. + -- Считаем ключом строки (airplane_code, seat_no). SELECT 1 FROM stg.seats AS s WHERE s.batch_id = '{{ run_id }}'::text diff --git a/sql/stg/segments_load.sql b/sql/stg/segments_load.sql index 96154a5..86ee77b 100644 --- a/sql/stg/segments_load.sql +++ b/sql/stg/segments_load.sql @@ -32,7 +32,8 @@ JOIN stg.bookings_ext AS b ON t.book_ref = b.book_ref CROSS JOIN max_batch_ts AS mb WHERE b.book_date > mb.max_ts AND NOT EXISTS ( - -- Защита от дублей в рамках одного batch_id + -- Идемпотентность: при повторном запуске/ретрае не вставляем повторно те же строки в рамках текущего batch_id. + -- Считаем ключом строки (ticket_no, flight_id). SELECT 1 FROM stg.segments AS s WHERE s.batch_id = '{{ run_id }}'::text diff --git a/sql/stg/tickets_load.sql b/sql/stg/tickets_load.sql index d90027d..925ac80 100644 --- a/sql/stg/tickets_load.sql +++ b/sql/stg/tickets_load.sql @@ -32,7 +32,7 @@ JOIN stg.bookings_ext AS b ON ext.book_ref = b.book_ref CROSS JOIN max_batch_ts AS mb WHERE b.book_date > mb.max_ts AND NOT EXISTS ( - -- Защита от дублей: ticket_no в источнике уникален, и в stg его не дублируем. + -- Идемпотентность: ticket_no — бизнес-ключ билета, не вставляем его повторно (включая ретраи/повторные запуски DAG). SELECT 1 FROM stg.tickets AS t WHERE t.ticket_no = ext.ticket_no