Patrón 5: Mensajería asíncrona con consumidor idempotente - JuanHerreraP/Proyecto-MISO-Solventa-Grupo-11 GitHub Wiki

Problema

Solventa debe procesar eventos masivos, como siniestros paramétricos, sin bloquear la aplicación ni perder mensajes. Además, un mensaje repetido no debe generar pagos duplicados.

Solución

Se utilizan SNS y SQS para publicar, almacenar y procesar eventos de forma asíncrona.

Cada evento tendrá un identificador único. Antes de realizar un pago, el consumidor verifica si ese identificador ya fue procesado. Si está repetido, no ejecuta nuevamente la operación.

Aplicación en Solventa

El servicio de Siniestros publica el evento paramétrico en SNS. SNS lo envía a la cola SQS de pagos y el servicio de Cobros y Pagos lo procesa cuando tenga capacidad.

Los mensajes fallidos se reintentan y, después del límite definido, se envían a una cola de mensajes fallidos o DLQ.

Razonamiento

El patrón permite absorber picos de eventos sin exigir que todos sean procesados al mismo tiempo. La idempotencia protege las operaciones financieras frente a reintentos o mensajes duplicados.

Relación con los ASR

  • EC04 – Escalabilidad: permite absorber eventos masivos sin perder mensajes.
  • EC09 – Integridad: evita pagos duplicados o alterados.
  • EC10 – Trazabilidad: registra el evento que originó cada operación.
  • EC11 – Disponibilidad: los mensajes permanecen en la cola durante fallas temporales.

También soporta HU12, HU13, HU15 y HU20.

Ventajas

  • Absorbe picos de carga.
  • Evita bloquear al usuario.
  • Permite reintentos.
  • Reduce el riesgo de pagos duplicados.
  • Facilita rastrear cada evento.

Limitaciones

  • El resultado no siempre es inmediato.
  • Se deben manejar estados pendientes.
  • Puede existir entrega duplicada de mensajes.
  • Es necesario monitorear la DLQ.

Diagrama

flowchart TB
    External["Evento externo"]
    Claims["Servicio de Siniestros"]
    SNS["Amazon SNS<br/>Eventos de negocio"]
    SQS["Amazon SQS<br/>Pagos automáticos"]
    Consumer["Servicio de Cobros y Pagos"]
    Check{"¿Evento procesado?"}
    Redis[("Redis<br/>Control de idempotencia")]
    Database[("PostgreSQL<br/>Resultado definitivo")]
    Payment["Pasarela de Pagos"]
    DLQ["Cola DLQ"]

    External --> Claims
    Claims -->|Publica evento| SNS
    SNS --> SQS
    SQS --> Consumer
    Consumer --> Check
    Check -->|Consultar| Redis
    Check -->|No| Payment
    Payment --> Database
    Database --> Redis
    Check -->|Sí| Ignore["No repetir operación"]

    SQS -.->|Falla después de reintentos| DLQ
Loading
⚠️ **GitHub.com Fallback** ⚠️