Skip to main content

Idempotencia, reintentos, DLQ y reproceso manual

10.1 Escenarios de duplicados cubiertos​

#EscenarioMecanismo de defensa
E1Cliente reenvía POST por timeoutX-Idempotency-Key + UNIQUE(partnerId, idempotencyKey)
E2Partner envía misma externalReferenceUNIQUE(partnerId, companyId, documentType, externalReference) lógico o físico
E3Outbox publica dos veces (bug)processed_event UNIQUE eventId
E4Pub/Sub at-least-once deliveryIdempotent Consumer + processed_event(eventId)
E5Worker reinicia antes de ackprocessed_event + transaccionalidad
E6Fusion responde tarde; se agota ack deadline y Pub/Sub reentregaFusion idempotency key (TBD campo a usar requestId en flexfields)
E7Reproceso manualNuevo eventId; validación estado y restricciones de idempotencia ERP

10.2 Restricciones UNIQUE recomendadas en PostgreSQL​

ConstraintAlcanceComentario
purchase_order_request.requestId (PK)GlobalUUID único.
UNIQUE(partner_id, idempotency_key)API ingestionBloquea duplicado cliente en CREATE.
UNIQUE(event_id) en processed_eventPublisher/consumerDuplicado de eventos.
UNIQUE(partner_id, external_reference, company_id, document_type)DomainDuplicado documento origen; partial index WHERE external_reference IS NOT NULL.

10.3 Política de reintentos​

NivelMecanismoRetry policy TBD
Call Oracle Fusion adapterResilience4j Retry + exponential backoffmaxAttempts=3, initialInterval=2s, multiplier=2.0, maxInterval=30s.
Pub/Sub subscriptionDead Letter Policy + retry policyminimumBackoff=10s, maximumBackoff=10min, maxDeliveryAttempts= TBD 5..15
Outbox Publisher (publish)Resilience4j RetrymaxAttempts=5; si no, status=PUBLISH_FAILED_RETRY.
Idempotency Key (HTTP 409)No retry automático; cliente decide si reintentar con nueva key

10.4 Taxonomía de errores vs retry​

Categoría¿Retry?Estado final sugeridoHTTP Code (si aplica)Log levelAlerta
VALIDATION_ERRORNoVALIDATION_FAILED (posible reproceso manual tras regla fix)422WARNOpcional por rule spike
BUSINESS_ERRORNoREJECTED / FAILED422 / 409WARNTBD
TEMPORARY_ERRORSí (hasta máximo)RETRY_PENDING → FAILED → DLQ502 / 504ERRORSí
INTEGRATION_ERROR (Fusion 4xx funcional)NoFAILED (posible reproceso manual)422ERRORSí
AUTHENTICATION_ERRORSolo si es token refreshTEMPORARY_ERROR → FAILED401ERRORSí (client credentials rotos)
AUTHORIZATION_ERRORNoFAILED (configuración)403ERRORSí
TECHNICAL_ERRORSí (timeout DB? limitar)TEMPORARY → FAILED500ERRORSí
NON_RETRYABLE_ERRORNoFAILED → DLQ422 / 500FATALSí

10.5 DLQ​

  • Topic: nexus.purchase-order.dlq
  • Atributos mínimo: requestId, eventId, partnerId, original_topic, original_subscription, attempts, error_code, error_category.
  • Operación: Operador con role OPERATOR → API POST /requests/{requestId}/retry (validaciones: role, permisos partner, estado, evita duplicados, genera nuevo eventId, registra auditoría).

10.6 Reproceso manual​

10.7 Inbox Pattern (evaluación)​

Se evalúa no introducir Inbox adicional en MVP pues:

  • Pub/Sub ack mode manual + processed_event ya cubren idempotencia del consumer.
  • Outbox + DLQ + retry policy cubren e2e.
  • Si aparece necesidad de reconciliación programada por lotes, agregar inbox_event sin duplicar esfuerzo.