Ежедневная задача перезапустилась после ретрая, и выручка за дату удвоилась — найдите дефект дизайна, а не плохую строку
Ежедневная задача грузит вчерашнюю выручку в mart. После временного сбоя оркестратор перезапустил её, и выручка за дату вышла удвоенной. Баг не в плохой строке — он в дизайне загрузки. Найдите дефект и сделайте загрузку идемпотентной.
-- запускается ежедневно для :run_date
INSERT INTO revenue_daily (order_date, revenue)
SELECT order_date, SUM(amount) AS revenue
FROM orders
WHERE order_date = :run_date
GROUP BY order_date;
Ретрай запустил это второй раз за тот же :run_date. Исправьте так, чтобы повтор оставил revenue_daily без изменений.
Загрузка append-only — второй INSERT за тот же :run_date задваивает дату. Сделать идемпотентной, заменяя дату каждый запуск: DELETE строк :run_date, затем INSERT, или MERGE — чтобы повтор перезаписывал, а не дописывал.
- ✗Винить плохую строку, а не сам append-only дизайн загрузки
- ✗Гасить удвоение через AVG вместо замены даты
- ✗Дедуплицировать при чтении вместо идемпотентной записи
- →Почему DELETE-затем-INSERT партиции даты делает загрузку идемпотентной?
- →Как unique-ограничение на order_date вскрыло бы этот баг раньше?
The bug is the load design, not the data — the INSERT appends rows. A second run for the same :run_date adds another aggregated row and the date doubles. Make the load idempotent by replacing the target date's rows instead of appending:
-- идемпотентно: заменяем партицию даты каждый запуск
BEGIN;
DELETE FROM revenue_daily WHERE order_date = :run_date;
INSERT INTO revenue_daily (order_date, revenue)
SELECT order_date, SUM(amount) AS revenue
FROM orders
WHERE order_date = :run_date
GROUP BY order_date;
COMMIT;
Обёрнутые в одну транзакцию, DELETE + INSERT дают повтор, который заменяет дату, а не дописывает — вывод за дату становится чистой функцией входа. Портируемые альтернативы — MERGE (upsert по order_date) или INSERT OVERWRITE партиции. AVG и SELECT DISTINCT при чтении лишь маскируют симптом: сама запись остаётся неидемпотентной, и следующий ретрай снова удвоит.