Saltar a contenido

Recipient List

1. Nombre del Patrón

  • Nombre oficial: Recipient List
  • Categoría: Message Routing (Enrutamiento de Mensajes)
  • Traducción contextual: Lista de Destinatarios

2. Resumen Ejecutivo

Recipient List es el patrón que recibe un mensaje y lo envía a un conjunto de destinatarios determinado dinámicamente en función del contenido del mensaje. A diferencia de Content-Based Router (que envía a un destino) y de Publish-Subscribe (que envía a todos los suscriptores), Recipient List envía a un subconjunto seleccionado de destinatarios posibles. Es el equivalente en mensajería de una lista de distribución de correo electrónico donde los destinatarios se determinan por el contenido del mensaje, no por una suscripción estática.

El problema que resuelve es la distribución selectiva: un mensaje debe llegar a múltiples consumidores, pero no a todos los consumidores disponibles, y el conjunto de destinatarios varía según el contenido del mensaje. Sin Recipient List, el productor tendría que enviar múltiples copias del mensaje a diferentes canales manualmente, o usar Publish-Subscribe y confiar en que cada suscriptor filtre lo que no le corresponde.

Este patrón es fundamental en sistemas de notificaciones regulatorias, distribución de eventos a stakeholders seleccionados, fan-out selectivo en event-driven architectures y cualquier escenario donde "¿a quién le interesa este mensaje?" tiene una respuesta que depende del propio mensaje. Su implementación moderna se encuentra en reglas multi-target de Amazon EventBridge, fan-out de SNS con filter policies, Azure Event Grid con múltiples subscriptions y orchestraciones de Step Functions que invocan múltiples targets en paralelo.


3. Definición Detallada

Propósito

Recipient List consume un mensaje, determina dinámicamente la lista de destinatarios que deben recibirlo (basándose en el contenido del mensaje, una tabla de lookup o una combinación), y envía una copia del mensaje a cada destinatario de la lista. El mensaje original se reproduce y distribuye a un subconjunto de canales de salida.

Lógica Arquitectónica

En muchas arquitecturas de integración, un mensaje necesita llegar a múltiples consumidores, pero la lista de consumidores no es fija ni universal:

  • Con Publish-Subscribe: el mensaje llega a todos los suscriptores. Cada suscriptor recibe todo y filtra lo que no le interesa. Esto funciona cuando todos o la mayoría de los suscriptores quieren la mayoría de los mensajes, pero es ineficiente cuando solo una pequeña fracción de los suscriptores está interesada en cada mensaje.
  • Con Content-Based Router: el mensaje llega a exactamente un destino. Esto funciona cuando hay un único procesador correcto por mensaje, pero no cuando múltiples consumidores deben procesarlo.
  • Con Recipient List: el mensaje llega exactamente a los destinatarios que lo necesitan. No más (como en pub-sub), no menos (como en routing a uno).

Recipient List es, conceptualmente, la unión de Content-Based Router (evaluación de contenido para decidir destino) y Publish-Subscribe (distribución a múltiples consumidores), pero con la precisión de enviar solo a los que corresponde.

Recipient List Estática vs. Dinámica

  • Recipient List estática: la lista de destinatarios está hardcodeada o en configuración fija. Ejemplo: "toda orden de compra va a inventario, facturación y shipping". La lista no cambia según el contenido del mensaje.
  • Recipient List dinámica: la lista se calcula en runtime basándose en el contenido del mensaje. Ejemplo: "una notificación de derrame químico va a las agencias regulatorias del país donde ocurrió el derrame, que varían según jurisdicción". La lista depende del mensaje.

La variante dinámica es la más potente y la que distingue este patrón de un simple fan-out estático.

Distinción con Publish-Subscribe

Aspecto Publish-Subscribe Recipient List
Destinatarios Todos los suscriptores Subconjunto seleccionado
Selección Por suscripción (al canal) Por contenido (del mensaje)
Conocimiento El publicador no sabe quién recibe El router calcula quién recibe
Eficiencia Ineficiente si pocos suscriptores relevantes Eficiente: solo destinatarios relevantes
Acoplamiento Bajo (productor no conoce suscriptores) Medio (router conoce lógica de selección)

Contexto en el que Emerge

Recipient List emerge cuando un mensaje debe distribuirse a un subconjunto variable de destinatarios. Es especialmente frecuente en:

  • Sistemas regulatorios donde diferentes agencias gubernamentales deben ser notificadas según el tipo, severidad y jurisdicción de un evento.
  • Plataformas de integración B2B donde un documento comercial debe enviarse a múltiples partners seleccionados.
  • Sistemas de notificaciones donde los canales de notificación (email, SMS, push, webhook) se seleccionan según las preferencias del usuario y el tipo de evento.

4. Problema que Resuelve

El Problema Antes del Patrón

Un organismo gubernamental de protección ambiental gestiona notificaciones de incidentes ambientales. Cuando ocurre un incidente (derrame químico, emisión tóxica, contaminación de agua), múltiples agencias deben ser notificadas, pero la lista de agencias varía según el tipo de incidente, su severidad y su ubicación geográfica:

  • Un derrame químico en zona costera debe notificarse a: Agencia de Protección Ambiental, Autoridad Marítima, Servicio de Emergencias, Gobierno Regional y (si afecta a aguas internacionales) la Organización Marítima Internacional.
  • Una emisión tóxica atmosférica debe notificarse a: Agencia de Protección Ambiental, Autoridad Sanitaria, Servicio de Emergencias y Gobierno Regional.
  • Un vertido a cauce fluvial debe notificarse a: Agencia de Protección Ambiental, Confederación Hidrográfica, Autoridad Sanitaria y Gobierno Regional.

Sin Recipient List, las alternativas son:

  • El productor envía a cada agencia: el sistema de gestión de incidentes debe conocer todas las agencias, sus protocolos y las reglas de qué agencias corresponden a cada tipo de incidente. El productor se convierte en un router complejo.
  • Publish-Subscribe a todas las agencias: todas las agencias reciben todas las notificaciones y filtran las que no les corresponden. La Autoridad Marítima recibe notificaciones de emisiones atmosféricas que descarta. Esto es aceptable con pocas agencias pero se degrada con docenas.

Síntomas del Problema

  • Productores con lógica compleja de distribución que crece con cada nueva agencia o tipo de incidente.
  • Agencias que reciben y descartan un alto porcentaje de notificaciones irrelevantes.
  • Dificultad para responder a la pregunta "¿a quién se notificó este incidente?" porque la lógica de distribución está dispersa.
  • Nuevos tipos de incidente o nuevas agencias que requieren cambios en el productor.
  • Notificaciones perdidas porque el productor no incluía a una agencia que debía ser notificada.

Impacto Operativo y Arquitectónico

Sin distribución selectiva centralizada:

  • La lógica de "¿a quién notificar?" se dispersa entre el productor y los consumidores.
  • La adición de una nueva agencia requiere cambios en el productor.
  • No existe un punto único donde verificar que un incidente fue correctamente distribuido a todas las agencias correspondientes.
  • La auditoría regulatoria (demostrar que todas las agencias requeridas fueron notificadas) es difícil sin un registro centralizado de distribución.

Riesgos Si No Se Implementa Correctamente

  • Notificación incompleta: una agencia que debía ser notificada no lo fue porque la lógica de selección tenía un bug o una omisión.
  • Notificación duplicada: la misma agencia recibe múltiples copias del mismo incidente por diferentes rutas.
  • Latencia de distribución: si la distribución es secuencial (una agencia tras otra), la última agencia recibe la notificación significativamente más tarde que la primera.
  • Fallo parcial: si la distribución a una agencia falla, ¿se notifica a las demás? ¿Se reintenta la fallida?

Ejemplos Reales

  • Gobierno — Protección ambiental: notificaciones de incidentes ambientales a agencias regulatorias según tipo, severidad y jurisdicción.
  • Finanzas — Reporting regulatorio: reportes financieros que deben enviarse a múltiples reguladores (banco central, comisión de valores, organismo fiscal) según el tipo de entidad y jurisdicción.
  • Supply chain: una orden de compra que debe notificarse al proveedor, al transportista, al almacén receptor y al departamento de calidad, pero no todos los participantes aplican a todas las órdenes.
  • Healthcare: un resultado de laboratorio crítico que debe notificarse al médico tratante, al jefe de servicio y (si es una enfermedad de declaración obligatoria) a las autoridades sanitarias.

5. Contexto de Aplicación

Cuándo Usarlo

  • Cuando un mensaje debe distribuirse a múltiples destinatarios y la lista varía según el contenido del mensaje.
  • Cuando Publish-Subscribe es demasiado amplio (no todos los suscriptores quieren todos los mensajes) y Content-Based Router es demasiado estrecho (más de un destino por mensaje).
  • Cuando se necesita un registro centralizado de a quién se distribuyó cada mensaje.
  • Cuando las reglas de distribución son una preocupación de negocio que debe gestionarse independientemente del productor.

Cuándo No Usarlo

  • Si cada mensaje va a exactamente un destino: use Content-Based Router.
  • Si cada mensaje va a todos los suscriptores sin excepción: use Publish-Subscribe Channel.
  • Si la distribución es siempre a los mismos destinatarios fijos: un fan-out estático (SNS → N SQS queues) es más simple.
  • Si la respuesta de los destinatarios debe consolidarse: combine Recipient List con Scatter-Gather o Aggregator.

Precondiciones

  • El mensaje contiene la información necesaria para determinar la lista de destinatarios.
  • Existe un mecanismo para resolver "contenido del mensaje → lista de destinatarios" (lookup table, reglas, servicio).
  • Los canales de los destinatarios están creados y con consumidores activos.

Restricciones

  • La distribución a múltiples destinatarios no es transaccional en la mayoría de los sistemas: si falla la distribución a un destinatario después de haber distribuido a otros, hay inconsistencia.
  • El orden de distribución puede importar en algunos escenarios (notificar al servicio de emergencias antes que al gobierno regional).
  • El número de destinatarios por mensaje debe ser acotado para evitar fan-out excesivo.

Dependencias

  • Canal de entrada con mensajes disponibles.
  • Tabla o servicio de lookup de destinatarios.
  • Canales de salida para cada destinatario posible.
  • Mecanismo de distribución (secuencial o paralelo).

Supuestos Arquitectónicos

  • La lista de destinatarios se puede calcular a partir del contenido del mensaje sin efectos colaterales.
  • Los destinatarios procesan el mensaje de forma independiente (no hay dependencias entre las entregas).
  • El fallo en la distribución a un destinatario no debe impedir la distribución a los demás.

Tipo de Sistemas Donde Aparece con Más Frecuencia

  • Sistemas gubernamentales y regulatorios (notificaciones a múltiples agencias).
  • Plataformas de integración B2B (distribución de documentos comerciales a partners).
  • Sistemas de notificaciones multicanal (email + SMS + push según preferencias).
  • Event-driven architectures con distribución selectiva (fan-out a subconjunto de microservicios).

6. Fuerzas Arquitectónicas

Precisión vs. Simplicidad

Recipient List ofrece precisión máxima en la distribución (cada mensaje va exactamente a quienes lo necesitan), pero a costa de complejidad en la lógica de selección y en la distribución a múltiples canales. Publish-Subscribe es más simple pero menos precisa. La tensión entre ambas se resuelve según el costo de la imprecisión: si recibir un mensaje irrelevante es barato, pub-sub basta; si es costoso (agencias regulatorias procesando notificaciones irrelevantes), Recipient List justifica su complejidad.

Fan-Out vs. Consistencia

Distribuir a N destinatarios en paralelo es eficiente pero introduce el problema de fallo parcial: ¿qué ocurre si 4 de 5 distribuciones tienen éxito y la quinta falla? ¿Se reintenta la quinta? ¿Se revierten las cuatro exitosas (compensación)? ¿Se acepta la inconsistencia?

Centralización de la Lógica de Selección vs. Acoplamiento

Centralizar las reglas de selección de destinatarios en el Recipient List permite un punto único de control y auditoría. Pero el componente se acopla tanto al contenido del mensaje (para evaluarlo) como a la topología de destinatarios (para distribuir). Cambios en cualquiera de los dos requieren cambios en el Recipient List.

Latencia de Distribución vs. Fiabilidad

Distribución paralela minimiza latencia (todos reciben casi simultáneamente) pero complica el manejo de errores. Distribución secuencial simplifica el manejo de errores (se puede detener en el primer fallo) pero introduce latencia creciente con el número de destinatarios.

Lógica de Selección Estática vs. Dinámica

Las reglas estáticas (lookup table) son simples y predecibles. Las reglas dinámicas (calculadas en runtime, posiblemente con lookups a servicios externos) son más potentes pero más complejas y con más puntos de fallo.

Auditoría vs. Overhead

Registrar la lista de destinatarios de cada mensaje es fundamental para compliance y debugging, pero añade overhead de storage y processing. El compromiso típico es registrar la distribución de forma asíncrona (log, evento de auditoría) sin bloquear el flujo principal.


7. Estructura Conceptual del Patrón

Actores o Componentes Involucrados

  1. Productor (Sender): envía mensajes al canal de entrada sin conocimiento de distribución.
  2. Canal de Entrada (Input Channel): canal donde llegan mensajes para distribución.
  3. Recipient List Router: componente que determina la lista de destinatarios y distribuye el mensaje.
  4. Recipient Resolver: lógica o tabla que mapea contenido del mensaje a lista de destinatarios.
  5. Canales de Salida (Output Channels): canales de cada destinatario posible.
  6. Destinatarios (Recipients): consumidores que procesan el mensaje distribuido.
  7. Registro de Distribución (Distribution Log): registro de qué mensajes se distribuyeron a qué destinatarios.

Flujo Lógico

flowchart TD
    A([Productor]) --> B[(Canal de Entrada)]
    B --> C[Recipient List Router\nconsume mensaje]
    C --> D[Invocar Recipient Resolver\ncon contenido del mensaje]
    D --> E[Evaluar reglas y retornar\nlista de destinatarios]
    E --> F[Para cada destinatario\nproducir copia del mensaje]
    F --> G[(Canal Destinatario 1)]
    F --> H[(Canal Destinatario 2)]
    F --> I[(Canal Destinatario N)]
    F --> J[Registrar distribución\nmessage_id, recipient, timestamp]
    J --> K[Hacer ack del mensaje\nen canal de entrada]
    G --> L[Destinatario 1 procesa\nindependientemente]
    H --> M[Destinatario 2 procesa\nindependientemente]
    I --> N[Destinatario N procesa\nindependientemente]
    L --> O([Fin])
    M --> O
    N --> O

Responsabilidades

Componente Responsabilidad
Productor Enviar mensaje con información suficiente para determinar destinatarios
Recipient List Router Determinar destinatarios, distribuir copias, registrar distribución
Recipient Resolver Mapear contenido del mensaje a lista de destinatarios
Canales de Salida Transportar el mensaje a cada destinatario
Destinatarios Procesar el mensaje de forma independiente
Distribution Log Registrar qué se distribuyó a quién para auditoría

Interacciones

  • Canal de Entrada → Router: consumo del mensaje original.
  • Router → Resolver: consulta de la lista de destinatarios.
  • Router → Canal de Salida (×N): producción de copias del mensaje.
  • Router → Distribution Log: registro de la distribución para auditoría.
  • Canal de Salida → Destinatario: entrega del mensaje a cada destinatario.

Contratos Implícitos

  • El mensaje contiene los campos necesarios para que el Resolver determine los destinatarios.
  • Cada destinatario puede procesar el mensaje independientemente (no hay dependencias entre destinatarios).
  • El Registro de Distribución es consultable para auditoría: "¿a quién se distribuyó el incidente X?".

Decisiones de Diseño Clave

  1. Distribución paralela vs. secuencial: ¿se envía a todos simultáneamente o uno por uno?
  2. Manejo de fallo parcial: ¿se reintenta el fallido? ¿Se continúa con los demás? ¿Se revierte todo?
  3. Resolver estático vs. dinámico: ¿lookup table fija o cálculo en runtime?
  4. Copias vs. referencias: ¿se envía una copia completa del mensaje a cada destinatario o una referencia (claim check)?
  5. Ack strategy: ¿se hace ack del canal de entrada después de distribuir a todos, o después de distribuir a al menos uno?

8. Ejemplo Arquitectónico Detallado

Dominio: Gobierno — Notificaciones Regulatorias de Incidentes Ambientales

Contexto del Negocio

La Agencia Nacional de Protección Ambiental opera un sistema de notificación de incidentes que gestiona los reportes de eventos ambientales en el territorio nacional. Cuando se reporta un incidente (derrame químico, emisión tóxica, contaminación de aguas, incendio forestal), el sistema debe notificar automáticamente a todas las agencias y entidades regulatorias que correspondan según el tipo de incidente, su severidad, su ubicación geográfica y los recursos naturales afectados.

Las agencias potenciales son 15 entidades gubernamentales y 8 organismos internacionales. Para cada incidente, entre 3 y 12 agencias deben ser notificadas. La lista varía completamente según las características del incidente.

Necesidad de Integración

El sistema de reportes de incidentes genera notificaciones que deben distribuirse a un subconjunto variable de agencias. La distribución debe ser auditable (demostrar que todas las agencias requeridas fueron notificadas), confiable (ninguna agencia se queda sin notificar) y rápida (los servicios de emergencia deben notificarse en menos de 60 segundos).

Sistemas Involucrados

  1. Incident Reporting Service: recibe reportes de incidentes de ciudadanos, empresas y sensores.
  2. Recipient List Router: determina las agencias destinatarias y distribuye la notificación.
  3. Agency Resolver: componente que evalúa las reglas de distribución y retorna la lista de agencias.
  4. Distribution Registry: base de datos que registra cada distribución para auditoría.
  5. Agency Notification Adapters: adaptadores para cada agencia (distintos protocolos: REST, SOAP, email, fax).
  6. Retry Handler: maneja reintentos de distribuciones fallidas.

Agencias y Reglas de Distribución

distribution_rules:
  - type: "CHEMICAL_SPILL"
    recipients:
      always:
        - AGENCIA_AMBIENTAL
        - SERVICIO_EMERGENCIAS
      if_coastal:
        - AUTORIDAD_MARITIMA
      if_international_waters:
        - ORGANIZACION_MARITIMA_INTL
      by_region:
        - GOBIERNO_REGIONAL_{region}
      if_severity_critical:
        - MINISTERIO_INTERIOR
        - PRESIDENCIA_GOBIERNO

  - type: "TOXIC_EMISSION"
    recipients:
      always:
        - AGENCIA_AMBIENTAL
        - AUTORIDAD_SANITARIA
        - SERVICIO_EMERGENCIAS
      by_region:
        - GOBIERNO_REGIONAL_{region}
      if_near_population:
        - PROTECCION_CIVIL
      if_severity_critical:
        - MINISTERIO_SANIDAD

  - type: "WATER_CONTAMINATION"
    recipients:
      always:
        - AGENCIA_AMBIENTAL
        - CONFEDERACION_HIDROGRAFICA_{basin}
        - AUTORIDAD_SANITARIA
      by_region:
        - GOBIERNO_REGIONAL_{region}
      if_drinking_water:
        - MINISTERIO_SANIDAD
        - EMPRESA_AGUA_MUNICIPAL_{municipality}

Restricciones Técnicas

  • Latencia máxima para notificar a Servicio de Emergencias: 60 segundos.
  • Todas las agencias correspondientes deben ser notificadas; la omisión tiene consecuencias legales.
  • Cada agencia tiene un protocolo diferente (REST, SOAP, email, fax).
  • La distribución a cada agencia debe registrarse con timestamp, status y número de reintentos.
  • Si una distribución falla, se reintenta hasta 5 veces. Después de 5 fallos, se escala a un operador humano.

Diseño del Recipient List

Canal Contenido Consumidor
incidents.reported Incidentes normalizados Recipient List Router
notifications.agencia_ambiental Notificaciones para la Agencia Ambiental Adapter REST
notifications.autoridad_maritima Notificaciones para la Autoridad Marítima Adapter SOAP
notifications.servicio_emergencias Notificaciones para el Servicio de Emergencias Adapter REST (priority)
notifications.gobierno_regional.{id} Notificaciones por gobierno regional Adapter email/REST
notifications.failed Distribuciones fallidas para retry Retry Handler

Decisiones Arquitectónicas

  1. Distribución paralela con prioridad: la distribución se realiza en paralelo para minimizar latencia, pero el Servicio de Emergencias tiene prioridad y se notifica primero (antes de distribuir al resto).

  2. Registro de distribución completo: cada distribución genera un registro en la Distribution Registry con campos: incident_id, agency_id, notification_channel, timestamp_sent, status (SENT, DELIVERED, FAILED, RETRYING), retry_count.

  3. Canal por agencia con adapter: cada agencia tiene su propio canal de notificación y un adapter que traduce al protocolo específico de la agencia. Esto permite que el router distribuya sin conocer los protocolos.

  4. Manejo de fallo parcial: si falla la distribución a una agencia, se produce al canal notifications.failed para retry. Las distribuciones a las demás agencias no se ven afectadas.

  5. Agency Resolver con reglas externalizadas: las reglas de distribución están en un almacén externo (YAML + base de datos) que permite añadir nuevas agencias o modificar criterios sin redespliegue.

Riesgos y Mitigaciones

Riesgo Mitigación
Agencia omitida en notificación Reglas validadas con tests, auditoría retroactiva
Fallo en distribución a una agencia Retry handler con 5 reintentos + escalación manual
Latencia excesiva para emergencias Prioridad de distribución a Servicio de Emergencias
Notificación duplicada a una agencia Idempotencia en adapters (deduplicación por incident_id)
Reglas de distribución incorrectas Validación, dry-run con incidentes sintéticos, auditoría

9. Desarrollo Paso a Paso del Ejemplo

Paso 1: Reporte de Incidente

Se reporta un derrame químico en la costa del Mediterráneo, zona marítima del Puerto de Valencia, severidad CRITICAL:

{
  "incident_id": "INC-2026-04-07-00391",
  "type": "CHEMICAL_SPILL",
  "severity": "CRITICAL",
  "timestamp": "2026-04-07T08:45:00Z",
  "location": {
    "lat": 39.4699,
    "lon": -0.3763,
    "region": "COMUNIDAD_VALENCIANA",
    "municipality": "VALENCIA",
    "coastal": true,
    "international_waters": false,
    "near_population": true
  },
  "substance": {
    "name": "Fuel Oil",
    "quantity_liters": 15000,
    "toxicity": "HIGH"
  },
  "reporter": {
    "type": "PORT_AUTHORITY",
    "id": "AUTH-VALENCIA-PORT"
  }
}

El Incident Reporting Service normaliza el reporte y lo publica en el canal incidents.reported.

Paso 2: Resolución de Destinatarios

El Recipient List Router consume el incidente y consulta al Agency Resolver:

  1. Tipo: CHEMICAL_SPILL → always: [AGENCIA_AMBIENTAL, SERVICIO_EMERGENCIAS].
  2. Coastal: true → add: [AUTORIDAD_MARITIMA].
  3. International waters: false → no add.
  4. Region: COMUNIDAD_VALENCIANA → add: [GOBIERNO_REGIONAL_CV].
  5. Severity: CRITICAL → add: [MINISTERIO_INTERIOR, PRESIDENCIA_GOBIERNO].
  6. Near population: true → add: [PROTECCION_CIVIL].

Lista final de destinatarios: [SERVICIO_EMERGENCIAS (priority), AGENCIA_AMBIENTAL, AUTORIDAD_MARITIMA, GOBIERNO_REGIONAL_CV, MINISTERIO_INTERIOR, PRESIDENCIA_GOBIERNO, PROTECCION_CIVIL]

Total: 7 agencias.

Paso 3: Distribución Priorizada

El Router distribuye con prioridad:

  1. Prioridad 0 (inmediato, antes de distribuir al resto):
  2. Produce al canal notifications.servicio_emergencias.
  3. Espera ack del broker.
  4. Registra: SERVICIO_EMERGENCIAS → SENT (08:45:02Z).

  5. Prioridad 1 (paralelo, después de emergencias):

  6. Produce en paralelo a los canales de las 6 agencias restantes.
  7. Espera ack del broker para cada uno.
  8. Registra cada distribución con timestamp y status.

Latencia total de distribución: 1.8 segundos (0.5s para emergencias + 1.3s para las 6 restantes en paralelo).

Paso 4: Procesamiento por Agencias

Cada agencia tiene su adapter que consume de su canal de notificación:

  • Servicio de Emergencias: adapter REST envía POST a https://api.112.gob.es/incidents con el incidente en formato JSON.
  • Autoridad Marítima: adapter SOAP envía a https://ws.marina.gob.es/NotificacionService con el incidente en XML.
  • Gobierno Regional CV: adapter email envía notificación certificada a emergencias@gva.es con adjuntos PDF.
  • Presidencia del Gobierno: adapter REST envía a la API de la Moncloa con nivel de seguridad clasificado.

Paso 5: Manejo de Fallo Parcial

La distribución al Gobierno Regional CV falla (timeout en el servidor de email):

  1. El adapter registra el fallo: GOBIERNO_REGIONAL_CV → FAILED (08:45:04Z, attempt 1, reason: timeout).
  2. Produce el mensaje al canal notifications.failed con metadata: agency, attempt, error.
  3. El Retry Handler consume del canal de failed y reintenta después de 30 segundos.
  4. Segundo intento exitoso: GOBIERNO_REGIONAL_CV → SENT (08:45:35Z, attempt 2).
  5. Se actualiza el registro de distribución.

Las distribuciones a las otras 6 agencias no se vieron afectadas por el fallo del Gobierno Regional.

Paso 6: Auditoría de Distribución

Un auditor regulatorio consulta el Distribution Registry para el incidente INC-2026-04-07-00391:

Agencia Status Timestamp Intentos
SERVICIO_EMERGENCIAS DELIVERED 08:45:02Z 1
AGENCIA_AMBIENTAL DELIVERED 08:45:03Z 1
AUTORIDAD_MARITIMA DELIVERED 08:45:03Z 1
GOBIERNO_REGIONAL_CV DELIVERED 08:45:35Z 2
MINISTERIO_INTERIOR DELIVERED 08:45:03Z 1
PRESIDENCIA_GOBIERNO DELIVERED 08:45:04Z 1
PROTECCION_CIVIL DELIVERED 08:45:03Z 1

Total: 7 agencias notificadas, 100% entregadas, latencia máxima 35 segundos (incluido retry del Gobierno Regional). Cumplimiento regulatorio completo.


10. Diagrama Técnico del Patrón

Código Python con diagrams

Diagrama General

Diagrama AWS

Diagrama Azure

Ver / Copiar código de los diagramas
from diagrams import Diagram, Cluster, Edge
from diagrams.onprem.queue import Kafka
from diagrams.onprem.compute import Server
from diagrams.onprem.database import PostgreSQL
from diagrams.onprem.monitoring import Grafana
from diagrams.onprem.client import User

with Diagram("Recipient List - Environmental Incident Notifications", show=False, direction="LR"):

    with Cluster("Incident Reporting"):
        reporters = User("Reporters\n(Citizens, Sensors)")
        intake = Server("Incident\nReporting Service")
        input_ch = Kafka("incidents.reported")

    with Cluster("Recipient List Router"):
        router = Server("Recipient\nList Router")
        resolver = Server("Agency\nResolver")
        rules = Server("Distribution\nRules (YAML)")
        dist_log = PostgreSQL("Distribution\nRegistry")

    with Cluster("Agency Notification Channels"):
        ch_emerg = Kafka("notif.servicio\n_emergencias")
        ch_ambiental = Kafka("notif.agencia\n_ambiental")
        ch_maritima = Kafka("notif.autoridad\n_maritima")
        ch_regional = Kafka("notif.gobierno\n_regional")
        ch_interior = Kafka("notif.ministerio\n_interior")
        ch_failed = Kafka("notif.failed\n(retry)")

    with Cluster("Agency Adapters"):
        adapt_emerg = Server("Adapter REST\n(112)")
        adapt_ambiental = Server("Adapter REST\n(Ambiental)")
        adapt_maritima = Server("Adapter SOAP\n(Marítima)")
        adapt_regional = Server("Adapter Email\n(Regional)")
        adapt_interior = Server("Adapter REST\n(Interior)")
        retry = Server("Retry\nHandler")

    monitoring = Grafana("Distribution\nMonitoring")

    # Intake flow
    reporters >> intake >> input_ch

    # Routing flow
    input_ch >> router
    rules >> Edge(style="dashed", label="rules") >> resolver
    router >> Edge(style="dashed", label="resolve") >> resolver
    router >> dist_log

    # Distribution flow (fan-out)
    router >> Edge(label="priority 0") >> ch_emerg >> adapt_emerg
    router >> ch_ambiental >> adapt_ambiental
    router >> ch_maritima >> adapt_maritima
    router >> ch_regional >> adapt_regional
    router >> ch_interior >> adapt_interior
    router >> Edge(style="dashed", label="on failure") >> ch_failed >> retry

    # Monitoring
    router >> Edge(style="dotted") >> monitoring
    dist_log >> Edge(style="dotted") >> monitoring
from diagrams import Diagram, Cluster, Edge
from diagrams.onprem.client import User
from diagrams.aws.compute import Lambda
from diagrams.aws.database import Dynamodb
from diagrams.aws.integration import SNS, SQS
from diagrams.aws.management import Cloudwatch


with Diagram("Recipient List - Environmental Incident Notifications (AWS)", show=False, direction="LR"):

    with Cluster("Incident Reporting"):
        reporters = User("Reporters\n(Citizens, Sensors)")
        intake = Lambda("Incident\nReporting Service")
        input_ch = SQS("incidents.reported")

    with Cluster("Recipient List Router"):
        router = Lambda("Recipient\nList Router")
        resolver = Lambda("Agency\nResolver")
        fan_out = SNS("SNS Incident\nFan-Out Topic")
        dist_log = Dynamodb("Dynamodb\nDistribution Log")

    with Cluster("Agency Notification Queues (SNS+SQS)"):
        ch_emerg = SQS("notif.servicio\n_emergencias")
        ch_ambiental = SQS("notif.agencia\n_ambiental")
        ch_maritima = SQS("notif.autoridad\n_maritima")
        ch_regional = SQS("notif.gobierno\n_regional")
        ch_interior = SQS("notif.ministerio\n_interior")
        ch_failed = SQS("notif.failed\n(DLQ retry)")

    with Cluster("Agency Adapters"):
        adapt_emerg = Lambda("Adapter REST\n(112)")
        adapt_ambiental = Lambda("Adapter REST\n(Ambiental)")
        adapt_maritima = Lambda("Adapter SOAP\n(Marítima)")
        adapt_regional = Lambda("Adapter Email\n(Regional)")
        adapt_interior = Lambda("Adapter REST\n(Interior)")
        retry = Lambda("Retry\nHandler")

    monitoring = Cloudwatch("Distribution\nMonitoring")

    # Intake flow
    reporters >> intake >> input_ch

    # Routing flow
    input_ch >> router
    router >> Edge(style="dashed", label="resolve") >> resolver
    router >> dist_log
    router >> fan_out

    # SNS fan-out to SQS subscriptions with filter policies
    fan_out >> Edge(label="filter: priority 0") >> ch_emerg >> adapt_emerg
    fan_out >> Edge(label="filter: ambiental") >> ch_ambiental >> adapt_ambiental
    fan_out >> Edge(label="filter: maritima") >> ch_maritima >> adapt_maritima
    fan_out >> Edge(label="filter: regional") >> ch_regional >> adapt_regional
    fan_out >> Edge(label="filter: interior") >> ch_interior >> adapt_interior
    fan_out >> Edge(style="dashed", label="on failure") >> ch_failed >> retry

    # Monitoring
    router >> Edge(style="dotted") >> monitoring
    dist_log >> Edge(style="dotted") >> monitoring
from diagrams import Diagram, Cluster, Edge
from diagrams.onprem.client import User
from diagrams.azure.compute import FunctionApps
from diagrams.azure.database import SQLServers
from diagrams.azure.devops import ApplicationInsights
from diagrams.azure.integration import ServiceBus, EventGridTopics


with Diagram("Recipient List - Environmental Incident Notifications (Azure)", show=False, direction="LR"):

    with Cluster("Incident Reporting"):
        reporters = User("Reporters\n(Citizens, Sensors)")
        intake = FunctionApps("Incident\nReporting Service")
        input_ch = EventGridTopics("incidents.reported\n(Event Grid Topic)")

    with Cluster("Recipient List Router"):
        router = FunctionApps("Recipient\nList Router")
        resolver = FunctionApps("Agency\nResolver")
        rules = FunctionApps("Distribution\nRules")
        dist_log = SQLServers("Azure SQL\n(Distribution Log)")

    with Cluster("Service Bus Agency Queues"):
        ch_emerg = ServiceBus("notif.servicio\n_emergencias")
        ch_ambiental = ServiceBus("notif.agencia\n_ambiental")
        ch_maritima = ServiceBus("notif.autoridad\n_maritima")
        ch_regional = ServiceBus("notif.gobierno\n_regional")
        ch_interior = ServiceBus("notif.ministerio\n_interior")
        ch_failed = ServiceBus("notif.failed\n(retry)")

    with Cluster("Agency Adapters"):
        adapt_emerg = FunctionApps("Adapter REST\n(112)")
        adapt_ambiental = FunctionApps("Adapter REST\n(Ambiental)")
        adapt_maritima = FunctionApps("Adapter SOAP\n(Marítima)")
        adapt_regional = FunctionApps("Adapter Email\n(Regional)")
        adapt_interior = FunctionApps("Adapter REST\n(Interior)")
        retry = FunctionApps("Retry\nHandler")

    monitoring = ApplicationInsights("Application\nInsights")

    # Intake flow
    reporters >> intake >> input_ch

    # Routing flow
    input_ch >> router
    rules >> Edge(style="dashed", label="rules") >> resolver
    router >> Edge(style="dashed", label="resolve") >> resolver
    router >> dist_log

    # Distribution flow (fan-out)
    router >> Edge(label="priority 0") >> ch_emerg >> adapt_emerg
    router >> ch_ambiental >> adapt_ambiental
    router >> ch_maritima >> adapt_maritima
    router >> ch_regional >> adapt_regional
    router >> ch_interior >> adapt_interior
    router >> Edge(style="dashed", label="on failure") >> ch_failed >> retry

    # Monitoring
    router >> Edge(style="dotted") >> monitoring
    dist_log >> Edge(style="dotted") >> monitoring

Explicación del Diagrama

El diagrama muestra la arquitectura completa del Recipient List para notificaciones ambientales:

  1. Incident Reporting: los reportes llegan al Incident Reporting Service y se publican en el canal incidents.reported.
  2. Recipient List Router: consume cada incidente, consulta al Agency Resolver para determinar la lista de agencias y distribuye copias a cada canal de agencia. Registra cada distribución en la Distribution Registry.
  3. Agency Notification Channels: un canal por agencia. Cada canal tiene un adapter que traduce al protocolo específico de la agencia.
  4. Failed Notifications: las distribuciones fallidas van a un canal de retry donde el Retry Handler las reintenta.
  5. Monitoring: Grafana muestra métricas de distribución, tasas de fallo y latencia por agencia.

Correspondencia Patrón ↔ Diagrama

Concepto del Patrón Componente del Diagrama
Productor Incident Reporting Service
Canal de Entrada incidents.reported
Recipient List Router Recipient List Router
Recipient Resolver Agency Resolver + Distribution Rules
Lista de Destinatarios Lista dinámica calculada por incidente
Canales de Salida Un canal por agencia
Destinatarios Agency Adapters (REST, SOAP, Email)
Registro de Distribución Distribution Registry (PostgreSQL)
Manejo de Fallos notif.failed + Retry Handler

11. Beneficios

Impacto Técnico

  • Distribución precisa: cada incidente se notifica exactamente a las agencias que corresponden. Sin exceso (agencias irrelevantes) ni defecto (agencias omitidas).
  • Desacoplamiento del productor: el Incident Reporting Service no conoce las agencias ni sus protocolos. Solo publica el incidente y la distribución es responsabilidad del Recipient List.
  • Distribución paralela: las 7 agencias se notifican en paralelo (excepto la de emergencias que tiene prioridad), minimizando la latencia total.
  • Aislamiento de fallos: el fallo en una agencia no impide la notificación a las demás.

Impacto Organizacional

  • Compliance regulatorio: el registro de distribución demuestra auditoríamente que cada agencia fue notificada, con timestamp y evidencia de entrega.
  • Independencia de equipos: cada agencia tiene su adapter gestionado independientemente. El equipo que gestiona el adapter de la Autoridad Marítima no depende del equipo de la Agencia Ambiental.
  • Extensibilidad: añadir una nueva agencia requiere crear un adapter, un canal y una regla de distribución, sin modificar el router ni los adapters existentes.

Impacto Operacional

  • Visibilidad completa: para cada incidente, se puede consultar instantáneamente a quién se notificó, cuándo, por qué canal y con qué resultado.
  • Detección de fallos: las distribuciones fallidas son visibles inmediatamente y se manejan automáticamente (retry) o se escalan manualmente.
  • Métricas operacionales: latencia de distribución por agencia, tasa de fallos por agencia, volumen de notificaciones por tipo de incidente.

Beneficios de Mantenibilidad y Evolución

  • Reglas externalizadas: las reglas de distribución están en YAML + base de datos, modificables sin redespliegue.
  • Adapters independientes: cada adapter se puede actualizar, reemplazar o escalar sin afectar al router ni a los demás adapters.
  • Testing de distribución: con incidentes sintéticos (dry-run), se puede verificar que las reglas producen la lista correcta de agencias sin enviar notificaciones reales.

12. Desventajas y Riesgos

Complejidad Añadida

  • Fan-out management: distribuir a N destinatarios en paralelo requiere gestión de concurrencia, timeouts y fallos parciales.
  • Lógica de selección: las reglas de distribución (por tipo, severidad, región, características) pueden volverse complejas con muchas combinaciones.
  • Canal por agencia: el número de canales crece con el número de agencias potenciales. Con 23 agencias, hay 23 canales de notificación más los canales de control y retry.
  • Consistencia de distribución: en un fan-out de 7 agencias, ¿qué garantía existe de que todas recibieron exactamente la misma versión del incidente?

Riesgos de Mal Uso

  • Recipient List como Publish-Subscribe: si la lista de destinatarios es casi siempre la misma (las mismas 5 agencias para el 95% de los incidentes), un Publish-Subscribe con filtro en cada suscriptor es más simple.
  • Lógica de selección como lógica de negocio: si las reglas de selección se vuelven tan complejas que implementan políticas de negocio (priorización, escalación, workflows), el componente necesita un rules engine, no un Recipient List.
  • Fan-out excesivo: si un mensaje se distribuye a 50+ destinatarios, el fan-out puede saturar la infraestructura. En estos casos, un enfoque pub-sub con filtrado puede ser más eficiente.

Sobreingeniería

  • Recipient List para destinos fijos: si todos los incidentes siempre van a las mismas 3 agencias, un fan-out estático (SNS → 3 SQS) es infinitamente más simple.
  • Adapter por agencia cuando todas usan el mismo protocolo: si todas las agencias aceptan JSON via REST, un adapter genérico con configuración por agencia es mejor que N adapters.

Costos de Operación

  • N canales + N adapters: cada agencia tiene canal y adapter que monitorear, escalar y mantener.
  • Distribution Registry: almacenamiento creciente de registros de distribución.
  • Retry management: las distribuciones fallidas requieren reintentos, escalación y resolución.

Anti-Patterns Relacionados

  • Implicit Recipient List: el productor mantiene una lista interna de destinatarios y envía directamente a cada uno, sin un componente de Recipient List explícito. Esto dispersa la lógica y dificulta la auditoría.
  • Sync Fan-Out: distribuir sincrónicamente a todos los destinatarios, esperando la respuesta de cada uno antes de continuar. Esto acopla la latencia del productor a la del destinatario más lento.

13. Relación con Otros Patrones

Patrones Complementarios

  • Content-Based Router (este capítulo): el router envía a un destino; Recipient List envía a múltiples. Pueden combinarse: el router decide la categoría, y dentro de la categoría, Recipient List distribuye a las agencias.
  • Message Filter (este capítulo): cada agencia puede tener un Message Filter en su canal para filtrar subtipos de notificación que no le interesan.
  • Channel Adapter (Capítulo 3): los adapters de agencia que traducen a REST, SOAP, email son Channel Adapters.
  • Guaranteed Delivery (Capítulo 3): la distribución a cada agencia debe garantizar entrega (retry, dead-letter).
  • Wire Tap (Capítulo 3): un Wire Tap en cada canal de agencia permite copiar notificaciones a un canal de auditoría.

Patrones que Suelen Aparecer Antes o Después

  • Antes: Message Translator — normaliza el incidente a un formato canónico.
  • Antes: Content Enricher — enriquece el incidente con datos de georeferenciación o clasificación.
  • Después: cada agencia puede implementar su propio pipeline de procesamiento.

Combinaciones Comunes

  • Recipient List + Aggregator (= Scatter-Gather): distribuir a múltiples agencias y esperar confirmación de todas. Esto es Scatter-Gather: se envía a N destinatarios y se agrega las respuestas.
  • Content-Based Router + Recipient List: el router clasifica el incidente (químico, atmosférico, hídrico) y luego cada Recipient List distribuye a las agencias correspondientes a esa categoría.
  • Recipient List + Dead Letter Channel: notificaciones que fallan después de todos los reintentos van a dead-letter para intervención manual.

Diferencias con Patrones Similares

  • vs. Publish-Subscribe: pub-sub envía a todos los suscriptores; Recipient List envía a un subconjunto seleccionado dinámicamente.
  • vs. Content-Based Router: el router envía a uno; Recipient List envía a múltiples.
  • vs. Splitter: Splitter divide un mensaje en partes y envía cada parte a un destino diferente; Recipient List envía el mismo mensaje completo a múltiples destinos.
  • vs. Scatter-Gather: Scatter-Gather = Recipient List + Aggregator. Si se necesita consolidar las respuestas de los destinatarios, es Scatter-Gather. Si solo se necesita distribuir sin agregar respuestas, es Recipient List.

Encaje en un Flujo Mayor de Integración

Recipient List se ubica después del routing primario (por categoría de mensaje) y antes de los adapters de destino. En un flujo completo: el mensaje se recibe, se normaliza, se clasifica, se enriquece, se determina la lista de destinatarios, se distribuye y se registra. Recipient List es el componente de distribución en este flujo.


14. Relevancia Actual del Patrón

Evaluación: Relevancia Alta

Argumentación

Recipient List es un patrón de alta relevancia actual porque la distribución selectiva es una necesidad central en las arquitecturas modernas:

  • Amazon EventBridge: las reglas de EventBridge evalúan cada evento contra múltiples rules, y cada rule puede tener múltiples targets. Esto es exactamente un Recipient List: un evento se evalúa y se distribuye a los targets cuyas condiciones se cumplen. Si un evento coincide con 3 rules que apuntan a 3 targets diferentes, el evento se distribuye a los 3.
  • AWS SNS con filter policies: SNS distribuye mensajes a subscriptions cuyas filter policies coinciden. Esto implementa Recipient List a nivel de broker: cada subscription evalúa si quiere el mensaje.
  • Azure Event Grid: Event Grid recibe eventos y los distribuye a los event handlers cuyas subscriptions coinciden con el tipo de evento. Múltiples subscriptions pueden coincidir, distribuyendo el mismo evento a múltiples handlers.
  • Step Functions Parallel State: AWS Step Functions puede invocar múltiples targets en paralelo dentro de un estado Parallel, implementando distribución a múltiples destinatarios con manejo de errores integrado.
  • Kafka + fan-out pattern: producir el mismo mensaje a múltiples topics selectivamente basándose en su contenido.

Cómo Se Implementa Hoy

Plataforma Implementación Mecanismo
EventBridge Multiple rules + targets Content matching por rule
SNS Multiple subscriptions Filter policies
Azure Event Grid Multiple subscriptions Event type matching
Step Functions Parallel state Orchestration
Apache Camel recipientList() EIP Expression que retorna lista
Spring Integration @RecipientListRouter Annotation-based routing
MuleSoft Scatter-Gather Router con distribución paralela

Qué Parte Sigue Siendo Esencial

  • El concepto de distribución selectiva (no a todos, no a uno, sino a los que corresponde) como patrón de routing fundamental.
  • La necesidad de un Recipient Resolver que calcule la lista basándose en el contenido del mensaje.
  • El manejo de fallo parcial en distribuciones a múltiples destinatarios.
  • La auditoría de distribución como requisito de compliance.

15. Implementación en Arquitecturas Modernas

Amazon EventBridge (Multiple Rules)

// Rule 1: Agencia Ambiental (siempre)
{
  "source": ["incident-reporting"],
  "detail-type": ["IncidentReported"],
  "detail": {
    "type": ["CHEMICAL_SPILL", "TOXIC_EMISSION", "WATER_CONTAMINATION"]
  }
}
// Target: SQS queue agencia-ambiental

// Rule 2: Autoridad Marítima (solo coastal)
{
  "source": ["incident-reporting"],
  "detail-type": ["IncidentReported"],
  "detail": {
    "location": {
      "coastal": [true]
    }
  }
}
// Target: SQS queue autoridad-maritima

// Rule 3: Servicio de Emergencias (severity critical)
{
  "source": ["incident-reporting"],
  "detail-type": ["IncidentReported"],
  "detail": {
    "severity": ["CRITICAL"]
  }
}
// Target: Lambda servicio-emergencias-notifier

Un solo evento puede coincidir con las 3 rules y distribuirse a los 3 targets simultáneamente. EventBridge actúa como Recipient List nativo.

Apache Camel

from("kafka:incidents.reported")
    .recipientList(method(agencyResolver, "resolveRecipients"))
    .parallelProcessing()
    .stopOnException()
    .to("log:distribution-audit");
public class AgencyResolver {
    public String resolveRecipients(Exchange exchange) {
        Incident incident = exchange.getIn().getBody(Incident.class);
        List<String> recipients = new ArrayList<>();

        recipients.add("kafka:notifications.agencia_ambiental");

        if (incident.getLocation().isCoastal()) {
            recipients.add("kafka:notifications.autoridad_maritima");
        }
        if ("CRITICAL".equals(incident.getSeverity())) {
            recipients.add("kafka:notifications.servicio_emergencias");
            recipients.add("kafka:notifications.ministerio_interior");
        }
        recipients.add("kafka:notifications.gobierno_regional_" +
                        incident.getLocation().getRegion().toLowerCase());

        return String.join(",", recipients);
    }
}

AWS Step Functions (Parallel State)

{
  "Type": "Parallel",
  "Branches": [
    {
      "StartAt": "NotifyAgenciaAmbiental",
      "States": {
        "NotifyAgenciaAmbiental": {
          "Type": "Task",
          "Resource": "arn:aws:lambda:...:notify-agencia-ambiental",
          "End": true,
          "Retry": [{"ErrorEquals": ["States.ALL"], "MaxAttempts": 5}]
        }
      }
    },
    {
      "StartAt": "NotifyAutoridadMaritima",
      "States": {
        "NotifyAutoridadMaritima": {
          "Type": "Task",
          "Resource": "arn:aws:lambda:...:notify-autoridad-maritima",
          "End": true,
          "Retry": [{"ErrorEquals": ["States.ALL"], "MaxAttempts": 5}]
        }
      }
    }
  ]
}

Step Functions ofrece retry nativo, timeouts y manejo de errores por branch.

Azure Event Grid

Topic: incident-reported
  Subscription: agencia-ambiental
    Filter: eventType in ('ChemicalSpill', 'ToxicEmission', 'WaterContamination')
    Endpoint: https://api.agencia-ambiental.gob.es/notifications
  Subscription: autoridad-maritima
    Filter: data.location.coastal == true
    Endpoint: https://ws.marina.gob.es/notifications
  Subscription: servicio-emergencias
    Filter: data.severity == 'CRITICAL'
    Endpoint: https://api.112.gob.es/incidents

16. Consideraciones de Gobierno y Operación

Observabilidad

  • Métricas de distribución: por mensaje — número de destinatarios, latencia de distribución total, fallos por destinatario.
  • Métricas agregadas: distribución promedio de destinatarios por tipo de incidente, tasa de fallo por agencia, latencia p50/p95/p99 por agencia.
  • Distributed tracing: cada copia del mensaje distribuida debe llevar el mismo correlation ID del incidente original para trazabilidad end-to-end.
  • Distribution audit log: registro inmutable de cada distribución con incident_id, agency_id, timestamp, status, retry_count.

Monitoreo

  • Tasa de fallo por agencia: si una agencia tiene tasa de fallo > 5%, su adapter o su sistema receptor tiene problemas.
  • Latencia de distribución: si la distribución total supera el SLA (60 segundos para emergencias), hay un problema de performance.
  • Distribución completa: verificar que cada incidente se distribuyó a todas las agencias requeridas (comparando lista esperada vs. lista real).
  • Cola de retry: si el canal notifications.failed acumula mensajes, hay fallos recurrentes que requieren atención.

Versionado

  • Reglas de distribución versionadas: los cambios en las reglas (nueva agencia, nuevo criterio) deben registrarse con versión y changelog.
  • Replay capability: capacidad de redistribuir un incidente pasado con las reglas vigentes (por ejemplo, si se descubre que una agencia fue omitida por una regla incorrecta).

Seguridad

  • Clasificación de notificaciones: algunos incidentes pueden tener nivel de seguridad clasificado. Las notificaciones a Presidencia deben transmitirse por canales cifrados.
  • Control de acceso a reglas: solo personal autorizado puede modificar las reglas de distribución.
  • Auditoría de acceso: quién consultó el Distribution Registry y cuándo.

Manejo de Errores

  • Retry strategy por agencia: cada agencia puede tener una estrategia de retry diferente (emergencias: retry inmediato; gobierno regional: retry con backoff).
  • Escalación: después de N reintentos fallidos, escalación a un operador humano que contacta a la agencia por teléfono.
  • Dead-letter por agencia: distribuciones irrecuperables van a dead-letter con contexto completo para resolución manual.

Idempotencia

  • Cada agencia debe poder recibir la misma notificación múltiples veces (por retry) sin efectos duplicados. Deduplicación por incident_id en los adapters o en los sistemas receptores.

Performance

  • Distribución paralela: enviar a todos los destinatarios en paralelo para minimizar latencia total.
  • Connection pooling: los adapters deben reutilizar conexiones para evitar overhead de establecimiento.
  • Batch cuando sea posible: si múltiples incidentes van a la misma agencia, agruparlos en lotes.

Escalabilidad

  • El Recipient List Router escala horizontalmente con el canal de entrada.
  • Los adapters escalan independientemente según el volumen de su agencia.
  • El Distribution Registry debe soportar alto volumen de escrituras concurrentes.

17. Errores Comunes

No Manejar Fallo Parcial

El error más frecuente y más costoso. Si la distribución a la Autoridad Marítima falla y el router no tiene manejo de fallo parcial, hay dos escenarios malos: (a) el router aborta y ninguna agencia restante se notifica, o (b) el router ignora el fallo y la Autoridad Marítima nunca se entera del derrame costero. El manejo correcto es: continuar con las demás agencias, registrar el fallo, reintentar la fallida de forma asíncrona.

Confundir Recipient List con Publish-Subscribe

Si la lista de destinatarios es estable y todos quieren todos los mensajes, Publish-Subscribe es más simple y eficiente. Recipient List solo se justifica cuando la lista varía significativamente según el contenido del mensaje. Usar Recipient List donde pub-sub basta añade complejidad innecesaria.

Lista de Destinatarios Incompleta

Si las reglas de distribución no cubren todos los casos (un nuevo tipo de incidente sin reglas, una nueva región sin gobierno regional configurado), agencias que deberían notificarse no lo son. Las reglas deben revisarse periódicamente y validarse con tests que cubran todas las combinaciones de tipo × severidad × región.

Distribución Secuencial Cuando Debería Ser Paralela

Distribuir secuencialmente a 12 agencias donde cada distribución toma 2 segundos resulta en 24 segundos de latencia total. Si el SLA de emergencias es 60 segundos, se está consumiendo el 40% del presupuesto de latencia solo en distribución. Distribución paralela reduce esto a ~2 segundos.

No Registrar la Distribución

Sin un Distribution Registry, es imposible responder a la pregunta "¿a quién se notificó el incidente INC-2026-00391?". En un contexto regulatorio donde la omisión de notificación tiene consecuencias legales, la falta de registro es un riesgo de compliance inaceptable.

Recipient List Sin Ruta por Defecto

Si las reglas de distribución producen una lista vacía (ningún destinatario para un tipo de incidente inesperado), el incidente no se notifica a nadie y se pierde silenciosamente. Una lista vacía debe generar una alerta operacional y/o enviar el incidente a un canal de revisión manual.


18. Conclusión Técnica

Recipient List es el patrón de routing que completa el espectro de distribución de mensajes: mientras que Content-Based Router envía a uno y Publish-Subscribe envía a todos, Recipient List envía al subconjunto preciso de destinatarios que corresponde a cada mensaje. Esta precisión es su mayor valor y su mayor fuente de complejidad.

Cuándo aporta valor: en cualquier escenario donde un mensaje debe llegar a múltiples destinatarios y la lista varía según el contenido del mensaje. Notificaciones regulatorias, distribución de documentos B2B, notificaciones multicanal con preferencias por usuario y fan-out selectivo en event-driven architectures son los dominios donde Recipient List es insustituible.

Cuándo evita problemas importantes: una Recipient List bien implementada — con distribución paralela, manejo de fallo parcial, registro de distribución auditable y reglas de selección validadas — evita los problemas más graves: agencias no notificadas de incidentes que les corresponden, distribución inconsistente por fallos parciales no gestionados, y falta de evidencia de compliance en auditorías regulatorias.

Cuándo no conviene adoptarlo: si todos los suscriptores quieren todos los mensajes, Publish-Subscribe es más simple. Si cada mensaje va a un solo destino, Content-Based Router es suficiente. Si la lista de destinatarios es fija e invariable, un fan-out estático (SNS → N SQS) es trivial y no necesita la complejidad de cálculo dinámico de destinatarios.

Recomendación para arquitectos: implemente Recipient List con distribución paralela para minimizar latencia, manejo explícito de fallo parcial (continuar + retry + escalación), registro de distribución desde el día uno para auditoría y compliance, y reglas de selección externalizadas y testeables. En plataformas cloud, evalúe las implementaciones nativas (EventBridge multi-rule, SNS filter policies, Event Grid multi-subscription) antes de construir un Recipient List custom, ya que ofrecen distribución, retry y monitoreo integrados. El patrón es conceptualmente simple (enviar a una lista) pero operacionalmente complejo (fallo parcial, auditoría, idempotencia), y esa complejidad operacional es donde se debe invertir el esfuerzo de diseño.