Integración6 min de lectura

Notificaciones de Amazon SP-API: deduplicar y conciliar

Gestiona eventos de listados de Amazon SP-API con una bandeja de entrada SQLite probada: deduplica entregas, recupera tras un reinicio y rechaza lecturas ya superadas.

En esta página

Por ipvolt · Comprobado el 16 de septiembre de 2026

Persiste cada notificación de listado de Amazon validada junto con el trabajo que genera, en una sola transacción, antes de confirmar la entrega. Usa la notificación para programar una lectura del listado. Si otra notificación aceptada llega durante esa lectura, mantén el trabajo pendiente y vuelve a leer. Esto evita una condición de carrera local concreta: que un resultado en curso más antiguo borre una solicitud de actualización más reciente.

Esta guía es para desarrolladores con una aplicación SP-API autorizada y una canalización de entrega por EventBridge ya existente. La integración requiere tu propio adaptador de eventos validado y un adaptador autenticado de lectura de listados. El laboratorio SQLite descargable se ejecuta sin conexión con eventos sintéticos, un único worker de conciliación y la biblioteca estándar de Python; implementa las comprobaciones de persistencia y finalización entre esos adaptadores.

Método: ipvolt ejecutó la demo y 12 pruebas el 16 de septiembre de 2026 usando CPython 3.14.7 y SQLite 3.53.4. Python 3.11+ es el objetivo del código fuente; 3.11 no se ejercitó en esa ejecución registrada. No se probó ninguna cuenta de Amazon, petición a la API ni confirmación real de una cola.

Ejecuta el laboratorio local

Descarga y extrae el ZIP completo del laboratorio. Abre una terminal en el directorio que contiene consumer.py y ejecuta:

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

No hay paquetes que instalar. Ambos comandos usan bases de datos temporales. La demo imprime un JSON determinista; compáralo con la salida registrada.

El README documenta el contrato completo. Si lo prefieres, inspecciona individualmente consumer.py, demo.py, la suite de pruebas y el fixture sintético.

Normaliza un evento de confianza antes de almacenarlo

Las notificaciones de estado e incidencias de listados usan el flujo de trabajo de EventBridge de Amazon. Una cola SQS puede ser un destino de regla aguas abajo; eso es distinto de suscribirse mediante el flujo de trabajo SQS directo de SP-API. Sigue la configuración de EventBridge de Amazon para destinos, suscripciones y permisos de entrega.

Fija el tipo en bruto y la versión del payload en tu adaptador. Los nombres en minúsculas de abajo pertenecen a este laboratorio:

Tipo documentado por AmazonVersión del payloadTipo normalizado del laboratorio
LISTINGS_ITEM_STATUS_CHANGE1.0listing_status_changed
LISTINGS_ITEM_ISSUES_CHANGE2023-12-13listing_issues_changed

Amazon indica a los usuarios de la versión 1.0 de incidencias que migren a 2023-12-13. Los eventos de estado tratan de la creación, la eliminación y la disponibilidad para compra; los eventos de incidencias contienen resúmenes que pueden motivar una lectura más completa. No describen todos los problemas posibles de un listado. Tipos de notificación de Amazon.

Ambos payloads en bruto permiten que MarketplaceId esté ausente. Resuélvelo solo a través de configuración autorizada y de confianza; de lo contrario, retén el evento para investigarlo antes de crear un registro normalizado. Nunca suministres tu marketplace por defecto de forma silenciosa. El laboratorio exige vendedor, SKU y marketplace explícitos. Consulta el esquema de estado y el esquema de incidencias fijados.

También hay una inconsistencia de nombres: el enum de ese esquema de estado dice LISTINGS_ITEM_STATUS_CHANGED, mientras que su ejemplo y la documentación dicen LISTINGS_ITEM_STATUS_CHANGE. Mantén cualquier excepción de validación acotada, versionada y cubierta por las pruebas de tu adaptador. El laboratorio normalizado ni analiza ese sobre ni certifica su conformidad con el esquema.

Este es exactamente el primer registro sintético del fixture:

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() acepta este objeto como texto JSON. El adaptador debe validar primero el origen, el contexto de aplicación/suscripción, la autorización del vendedor y el alcance. Conserva la identidad interna de la notificación por separado del ID de evento externo de EventBridge y de cualquier receipt handle de la cola. El sobre de EventBridge y el contrato de eliminación de SQS describen esos valores de transporte distintos.

El laboratorio deduplica por (source, subscription, notification_id). Esta clave compuesta es una política de la aplicación. Mantén los contadores de intentos de entrega, los receipt handles y las horas de recepción fuera del objeto normalizado: cambian entre entregas. El README enumera sus límites estrictos de validación de campos, tamaño y JSON.

Confirma la aceptación y el trabajo pendiente juntos

EventBridge puede entregar duplicados y no ofrece ninguna garantía de orden. Una cola SQS estándar aguas abajo también permite duplicados y entregas fuera de orden. Comparativa de entrega de AWS, colas SQS estándar.

El núcleo ejecutable gestiona esa incertidumbre en cuatro pasos:

  1. Inicia una transacción SQLite. Para una identidad nueva, inserta el registro en la bandeja de entrada e incrementa la generación de trabajo de (seller_id, sku, marketplace_id) a la vez.
  2. Para una identidad existente, compara el contenido normalizado canónico. Un contenido idéntico devuelve duplicate sin incrementar el trabajo. Un contenido distinto lanza IdentityConflict y conserva el estado original.
  3. Devuelve may_ack=True solo después del commit. Es una decisión lógica para tu adaptador de transporte; la descarga no hace ninguna llamada de confirmación a la cola. Los errores de validación, conflicto y almacenamiento no producen esa decisión.
  4. Recorre dirty_keys() tras un reinicio y entre ejecuciones. Una clave está sucia cuando generation > applied_generation. Captura su generación, realiza la lectura fuera de la transacción y guarda el resultado solo si la clave y la generación siguen coincidiendo.

Cada identidad recién aceptada avanza su clave, incluido un evento con un event_time más antiguo. El payload se conserva para la comparación de identidad y nunca se aplica como estado actual del listado. El modelo de estado inspeccionado define EventTime como una marca de tiempo, no como una revisión compartida del listado. Este diseño no descarta trabajo solo porque su marca de tiempo sea más antigua.

Observa la carrera entre el reinicio y la lectura en curso

Esta traza compacta procede de la demo registrada para seller-A / SKU-RED / market-A:

CasoGeneraciónGeneración aplicadaSuciaResultado observado
El proceso termina tras el commit10trueSobrevive una fila en la bandeja de entrada
Reentrega tras el reinicio10trueduplicate, may_ack: true
Lectura sintética inicial11falseread-1 guardado
Llega un evento más antiguo21trueSe requiere una nueva actualización
Llega otro evento durante la lectura de la generación 231truecompletion_applied: false
La lectura siguiente falla31trueSe conserva la instantánea anterior
Actualización posterior exitosa33falseread-3 guardado

El resultado de la generación 2 no puede limpiar la generación 3. Su documento read-2 rechazado nunca reemplaza a read-1; el fallo posterior también deja el trabajo pendiente. La demo termina con cinco filas en la bandeja de entrada, tres claves limpias independientes y cero confirmaciones externas.

Las 12 pruebas registradas pasan. Incluyen una salida abrupta de un proceso hijo tras el commit, fallos de SQLite inyectados que revierten juntos la bandeja de entrada y el trabajo, identidades en conflicto, resultados con clave incorrecta y la carrera descrita arriba. Esto establece el comportamiento local ante reinicios del proceso, no la durabilidad ante cortes de energía o corrupción del sistema de archivos.

«Limpia» significa que se aceptó una lectura frente a la última generación local persistida. No puede demostrar que la respuesta de Amazon incluya el cambio que la desencadenó, que otra notificación no esté retrasada ni que la entrega haya sido completa. El contador no es una revisión de Amazon ni una garantía distribuida de exactamente una vez.

Valida la lectura antes de limpiar el trabajo

Tu adaptador de lectura debe elegir explícitamente los datasets de getListingsItem y validar el estado HTTP, el contenido de la respuesta y el significado previsto de vendedor/SKU/marketplace antes de devolver ReadResult. El tutorial de recuperación de listados de Amazon explica qué datasets responden a qué preguntas. Ahora admite varios marketplaces de la misma región para vendedores; este laboratorio mantiene deliberadamente un marketplace por clave de trabajo.

El núcleo no valida una respuesta real de Amazon. Comprueba la clave declarada por el adaptador, los límites del JSON y la generación local. Incluso {} pasa su comprobación de forma de objeto. Si faltan datos obligatorios, la respuesta pertenece a otro sitio o la petición falla, tu adaptador debe lanzar una excepción en lugar de devolver un marcador con forma de éxito. refresh_once() entonces deja el trabajo sucio y la instantánea anterior intacta.

Para la decisión aparte sobre envíos aceptados, ofertas actuales, inventario y observaciones desconocidas, usa Actualizaciones de listados de Amazon: aceptado no significa publicado. Una operación de almacenamiento exitosa no puede dar sentido a una observación incompleta.

Añade recuperación alrededor del núcleo

Usa un único worker de conciliación para este ejemplo. Sus tickets son comprobaciones de generación, no arrendamientos de worker. La base de datos conserva las identidades de la bandeja de entrada indefinidamente; eliminarlas cambia el horizonte de deduplicación. La programación, el backoff, los límites de peticiones, la retención y la propiedad por workers concurrentes requieren un diseño adicional.

Una canalización de producción también necesita un tratamiento duradero de los eventos malformados o en conflicto, recuperación ante fallos de entrega y conciliación periódica del alcance autorizado de listados. Amazon recomienda un mecanismo de recuperación de respaldo; EventBridge deja de reintentar cuando se agota su política configurada y admite una cola de mensajes fallidos (DLQ). Un barrido y la recuperación desde la DLQ quedan fuera de este laboratorio. Cubren fallos que una bandeja de entrada no puede ver porque el evento nunca llegó a ella.

ipvolt está en desarrollo. Únete a la lista de acceso anticipado para recibir un correo cuando se abra el acceso. Nada más.

Fuentes y lecturas adicionales

Referencias técnicas usadas para esta guía. Consulta la documentación de tu versión instalada y la configuración compatible de tu proveedor.