Интеграция6 мин чтения

Уведомления Amazon SP-API: дедупликация и сверка

Обработка событий листингов Amazon SP-API через протестированный SQLite-инбокс: дедупликация доставок, восстановление после перезапуска и отклонение устаревших чтений.

На этой странице

От ipvolt · Проверено 16 сентября 2026

Сохраняйте каждое проверенное уведомление о листинге Amazon вместе с работой, которую оно порождает, в одной транзакции, прежде чем подтверждать доставку. Используйте уведомление для планирования чтения листинга. Если во время этого чтения приходит ещё одно принятое уведомление, оставляйте работу ожидающей и читайте снова. Это предотвращает конкретную локальную гонку: более старый, ещё выполняющийся результат сбрасывает более новый запрос на обновление.

Это руководство предназначено для разработчиков с авторизованным приложением SP-API и существующим конвейером доставки EventBridge. Для интеграции нужны ваш собственный адаптер проверенных событий и аутентифицированный адаптер чтения листингов. Загружаемая лаборатория на SQLite работает офлайн с синтетическими событиями, одним воркером сверки и стандартной библиотекой Python; она реализует проверки сохранения и завершения между этими адаптерами.

Метод: ipvolt запустил демо и 12 тестов 16 сентября 2026 года на CPython 3.14.7 и SQLite 3.53.4. Целевая версия исходного кода — Python 3.11+; версия 3.11 в этом записанном прогоне не проверялась. Ни аккаунт Amazon, ни API-запросы, ни реальные подтверждения очереди не тестировались.

Запустите локальную лабораторию

Скачайте и распакуйте полный ZIP лаборатории. Откройте терминал в каталоге с consumer.py, затем выполните:

sh
python3 -B demo.py
python3 -B -m unittest -v test_consumer.py

Устанавливать пакеты не нужно. Обе команды используют временные базы данных. Демо печатает детерминированный JSON; сравните его с записанным выводом.

README документирует полный контракт. При желании изучите по отдельности consumer.py, demo.py, набор тестов и синтетическую фикстуру.

Нормализуйте доверенное событие перед сохранением

Уведомления о статусе и проблемах листинга используют рабочий процесс EventBridge Amazon. Очередь SQS может быть нижестоящей целью правила; это отличается от подписки через прямой рабочий процесс SP-API SQS. Следуйте настройке EventBridge от Amazon для назначений, подписок и разрешений на доставку.

Зафиксируйте сырой тип и версию полезной нагрузки в своём адаптере. Имена в нижнем регистре ниже принадлежат этой лаборатории:

Документированный тип AmazonВерсия полезной нагрузкиНормализованный тип лаборатории
LISTINGS_ITEM_STATUS_CHANGE1.0listing_status_changed
LISTINGS_ITEM_ISSUES_CHANGE2023-12-13listing_issues_changed

Amazon направляет пользователей версии 1.0 уведомлений о проблемах на миграцию к 2023-12-13. События статуса касаются создания, удаления и возможности покупки; события о проблемах содержат сводки, которые могут стать поводом для более полного чтения. Они не описывают все возможные проблемы листинга. Типы уведомлений Amazon.

Обе сырые полезные нагрузки допускают отсутствие MarketplaceId. Определяйте его только через доверенную авторизованную конфигурацию; иначе задержите событие для расследования, прежде чем создавать нормализованную запись. Никогда не подставляйте молча свой маркетплейс по умолчанию. Лаборатория требует явных продавца, SKU и маркетплейса. См. зафиксированные схему статуса и схему проблем.

Есть и несогласованность в именовании: в enum этой схемы статуса указано LISTINGS_ITEM_STATUS_CHANGED, тогда как её пример и документация говорят LISTINGS_ITEM_STATUS_CHANGE. Держите любое исключение в валидации узким, версионированным и покрытым тестами вашего адаптера. Нормализованная лаборатория не разбирает этот конверт и не подтверждает его соответствие схеме.

Это точная первая синтетическая запись из фикстуры:

json
{
  "schema_version": 1,
  "source": "fixture:eventbridge:bus-A",
  "subscription": "fixture-subscription-A",
  "notification_id": "notice-001",
  "seller_id": "seller-A",
  "sku": "SKU-RED",
  "marketplace_id": "market-A",
  "notification_type": "listing_status_changed",
  "event_time": "2026-09-16T10:00:00Z",
  "payload": {"hint": "synthetic status change"}
}

Store.ingest() принимает этот объект как JSON-текст. Адаптер сначала должен проверить источник, контекст приложения/подписки, авторизацию продавца и область действия. Храните внутреннюю идентичность уведомления отдельно от внешнего ID события EventBridge и любого receipt handle очереди. Конверт EventBridge и контракт удаления SQS описывают эти различные транспортные значения.

Лаборатория дедуплицирует по (source, subscription, notification_id). Этот составной ключ — политика приложения. Не включайте в нормализованный объект счётчики попыток доставки, receipt handle и время получения: они меняются между доставками. README перечисляет строгие ограничения на поля, размер и валидацию JSON.

Фиксируйте приём и ожидающую работу вместе

EventBridge может доставлять дубликаты и не гарантирует порядок. Нижестоящая стандартная очередь SQS также допускает дубликаты и доставку не по порядку. Сравнение способов доставки AWS, стандартные очереди SQS.

Исполняемое ядро обрабатывает эту неопределённость в четыре шага:

  1. Начните транзакцию SQLite. Для новой идентичности вставьте запись инбокса и увеличьте поколение работы для (seller_id, sku, marketplace_id) вместе.
  2. Для существующей идентичности сравните каноническое нормализованное содержимое. Идентичное содержимое возвращает duplicate без увеличения работы. Различающееся содержимое вызывает IdentityConflict и сохраняет исходное состояние.
  3. Возвращайте may_ack=True только после коммита. Это логическое решение для вашего транспортного адаптера; загружаемый код не делает ни одного вызова подтверждения очереди. Ошибки валидации, конфликта и хранения этого решения не порождают.
  4. Сканируйте dirty_keys() после перезапуска и между запусками. Ключ считается «грязным», когда generation > applied_generation. Зафиксируйте его поколение, выполните чтение вне транзакции, затем сохраните результат, только если ключ и поколение всё ещё совпадают.

Каждая новая принятая идентичность продвигает свой ключ, включая событие с более старым event_time. Полезная нагрузка хранится для сравнения идентичности и никогда не применяется как текущее состояние листинга. Изученная модель статуса определяет EventTime как метку времени, а не как общую ревизию листинга. Такая конструкция не отбрасывает работу лишь потому, что её метка времени старше.

Наблюдайте перезапуск и гонку с выполняющимся чтением

Эта компактная трассировка взята из записанного демо для seller-A / SKU-RED / market-A:

СлучайПоколениеПрименённое поколениеГрязныйНаблюдаемый результат
Процесс завершается после коммита10trueОдна строка инбокса сохраняется
Повторная доставка после перезапуска10trueduplicate, may_ack: true
Первое синтетическое чтение11falseread-1 сохранён
Приходит более старое событие21trueТребуется новое обновление
Ещё одно событие приходит во время чтения поколения 231truecompletion_applied: false
Следующее чтение завершается ошибкой31trueПредыдущий снимок сохранён
Более позднее успешное обновление33falseread-3 сохранён

Результат поколения 2 не может очистить поколение 3. Его отклонённый документ read-2 никогда не заменяет read-1; последующий сбой также оставляет работу ожидающей. Демо завершается с пятью строками инбокса, тремя независимыми чистыми ключами и нулём внешних подтверждений.

Все 12 записанных тестов проходят. Они включают жёсткое завершение дочернего процесса после коммита, внедрённые сбои SQLite, которые откатывают инбокс и работу вместе, конфликтующие идентичности, результаты с неверным ключом и описанную выше гонку. Это устанавливает локальное поведение при перезапуске процесса, а не устойчивость к потере питания или повреждению файловой системы.

«Чистый» означает, что чтение принято относительно последнего сохранённого локального поколения. Это не доказывает, что ответ Amazon включает вызвавшее его изменение, что другое уведомление не задерживается или что доставка была полной. Счётчик — не ревизия Amazon и не распределённая гарантия exactly-once.

Проверяйте чтение перед очисткой работы

Ваш адаптер чтения должен явно выбирать наборы данных getListingsItem и проверять HTTP-статус, содержимое ответа и предполагаемый смысл продавца/SKU/маркетплейса, прежде чем возвращать ReadResult. Руководство Amazon по получению листинга объясняет, какие наборы данных отвечают на какие вопросы. Теперь оно поддерживает несколько маркетплейсов одного региона для продавцов; эта лаборатория намеренно держит один маркетплейс на ключ работы.

Ядро не проверяет реальный ответ Amazon. Оно проверяет объявленный адаптером ключ, ограничения JSON и локальное поколение. Даже {} проходит его проверку формы объекта. Если обязательные данные отсутствуют, ответ относится к чему-то другому или запрос завершился ошибкой, ваш адаптер должен выбросить исключение, а не возвращать заглушку в форме успеха. Тогда refresh_once() оставляет работу грязной, а предыдущий снимок нетронутым.

Для отдельного решения о принятых отправках, текущих предложениях, запасах и неизвестных наблюдениях используйте Обновления листингов Amazon: «принято» не значит «опубликовано». Успешная операция сохранения не может сделать неполное наблюдение осмысленным.

Добавьте восстановление вокруг ядра

Используйте одного воркера сверки для этого примера. Его тикеты — проверки поколения, а не аренды воркеров. База данных хранит идентичности инбокса бессрочно; их удаление меняет горизонт дедупликации. Планирование, backoff, ограничения частоты запросов, хранение и владение при нескольких воркерах требуют дополнительного проектирования.

Производственному конвейеру также нужна надёжная обработка некорректных или конфликтующих событий, восстановление после сбоев доставки и периодическая сверка авторизованной области листингов. Amazon рекомендует резервный механизм получения; EventBridge прекращает повторы после исчерпания настроенной политики и поддерживает очередь недоставленных сообщений (dead-letter queue). Сканирующая сверка и восстановление из DLQ выходят за рамки этой лаборатории. Они покрывают сбои, которых инбокс не видит, потому что событие до него так и не дошло.

ipvolt находится в разработке. Запишитесь в список раннего доступа, чтобы получить одно письмо, когда доступ откроется. Больше ничего.

Источники и дополнительное чтение

Технические материалы, использованные при подготовке руководства. Сверяйтесь с документацией вашей версии и с поддерживаемой конфигурацией вашего провайдера.