Перейти к основному содержимому

0029. Высокочастотный сбор заказов/продаж РНП поверх оцифровки

Копия ADR из репозитория: backend/docs/adr/0029-rnp-orders-sales-sync.md. Канонический текст — в репозитории; портал обновляется командой npm run sync:adr.

  • Статус: accepted
  • Дата: 2026-06-29
  • Связанные задачи: OP-79 (5.6 · РНП), переиспользует OP-54 (оцифровка)

Контекст и проблема​

ТЗ 5.6: заказы и продажи собираются ежеминутно для оперативной аналитики РНП. Оцифровка (OP-54) уже импортирует те же фиды WB (/api/v1/supplier/orders, /api/v1/supplier/sales) в wb_orders/wb_sales идемпотентным upsert, и для неё есть ежедневный планировщик (OP-58, cron 03:00). Вопросы:

  1. Заводить ли отдельные сущности РНП для заказов/продаж?
  2. Как организовать ежеминутный сбор?
  3. Как обеспечить «инкрементальность без дублей» и лимиты WB?

Решение​

  • Переиспользуем оцифровку, не дублируя сущности: РНП-сбор вызывает WbImportService.importForAccountSystem(wbAccountId, dateFrom). Заказы/продажи остаются в wb_orders/wb_sales (по nmId, готовы к объединению по артикулу — OP-82). Так формулируют и соседние тикеты (OP-80/81 — «переиспользовать»).
  • Отдельный модуль rnp с интервальным расписанием (OP-42, 1 мин) → фан-аут-джоба → джоба импорта на кабинет (зеркало OP-58/OP-70). Очередь и имена расписания изолированы от оцифровки.
  • Дедупликация — идемпотентный upsert импорта (по saleId/srid); повтор за пересекающееся окно безопасен. Окно — lookback = 1 день (подхват свежих записей и правок lastChangeDate, которые WB вносит задним числом).

Последствия и known limitations (follow-up)​

  • Окно vs курсор. Текущая реализация на каждом тике запрашивает суточное окно (digitization flag=0, постранично), а не «дельту с последнего курсора». Это даёт корректные данные (идемпотентность убирает дубли), но при ежеминутном опросе создаёт повторную нагрузку на WB. Follow-up: курсорный инкремент (хранить lastChangeDate-курсор на кабинет и запрашивать только новее) — когда понадобится снизить нагрузку.
  • Лимиты WB. Соблюдение лимитов делегировано WB-клиенту/лимитеру (OP-34). Эндпоинты статистики WB лимитированы жёстко (~1 запрос/мин); при росте числа кабинетов и объёмов потребуется per-endpoint лимит для statistics:/supplier/* и согласование с ежедневной оцифровкой за общую корзину кабинета. Follow-up в рамках OP-34/нагрузочного тюнинга, вне scope OP-79.
  • Anti-overlap. Наложение прогонов отсекается детерминированным jobId (расписание — по окну; фан-аут — по account:minute-slot). Импорт кабинета, длящийся дольше минуты, теоретически может пересечься со следующим тиком; данные при этом не портятся (идемпотентный upsert), цена — лишний расход лимита.
  • Партиционирование fact-таблиц (ADR-0008, месячные партиции) — отдельный тикет OP-91; здесь не вводится.