Volver al inicio

Publish/Subscribe: el patrón que desacopla a quien envía de quien escucha

Camilo RojasCamilo Rojas
16 oct 2026
TutorialGuía
#patrones-de-diseño#pubsub#arquitectura#mensajería#gcp

**Publish/Subscribe** (o *pub/sub*) es un patrón de mensajería en el que quien produce un mensaje (el **publisher**) no lo envía a nadie en particular: lo publica en un **topic**, y todos los **subscribers** interesados en ese topic reciben su propia copia. Quien publica no sabe cuántos escuchan, ni quiénes son, ni siquiera si hay alguien escuchando.

<Callout theme="info" text="La idea en una frase: el publisher y el subscriber solo se ponen de acuerdo en el nombre del topic y en la forma del mensaje. Nada más." />

***

## El problema: servicios que se conocen demasiado

Imagina una tienda en línea. Cuando se crea un pedido, hay que enviar un correo de confirmación, descontar stock y registrar la venta en analítica. La forma ingenua es que el servicio de pedidos llame a cada uno:

* El servicio de pedidos **conoce** al de correos, al de inventario y al de analítica.
* Si el de correos está caído, el pedido falla o se queda esperando.
* Para sumar un cuarto consumidor (por ejemplo, un servicio antifraude) hay que **modificar y redesplegar** el servicio de pedidos.

Pub/sub invierte esa dependencia. El servicio de pedidos solo publica `orders` y se olvida. Cada servicio interesado se suscribe por su cuenta, y agregar o quitar uno no toca al publisher.

***

## Míralo funcionar

La figura es un banco de pruebas del patrón. Haz clic en un dispensador para publicar un mensaje, o en un interruptor para suscribir o desuscribir a un subscriber. Si no tocas nada, hace un recorrido por sí sola.

<PubSubFigure />

Cómo leerla:

* **Dispensadores = publishers.** El redondo publica `orders` y el cuadrado publica `alerts`. Sueltan el mensaje en su carril sin saber qué hay más adelante.
* **Carriles = topics.** Cada carril transporta un solo tipo de mensaje.
* **Interruptores = suscripciones.** Un interruptor encendido baja una prensa sobre el carril. Cuando un mensaje pasa por debajo, la prensa estampa una **copia** en la bandeja de ese subscriber.
* **Bandejas = subscribers.** La del medio escucha los dos topics y recibe fichas redondas y cuadradas. Las de los lados escuchan uno solo.

Prueba tres cosas:

1. **Fan-out.** Publica un `orders`: llega una copia a cada subscriber suscrito, y el original sigue su camino.
2. **Desacople.** Apaga una suscripción y vuelve a publicar. Esa bandeja deja de recibir y el publisher, el carril y los demás subscribers siguen igual.
3. **Nadie escucha.** Apaga todas las suscripciones de un topic y publica. El mensaje llega al final del carril y cae al desagüe: el publisher no se entera.

***

## Las piezas del patrón

* **Message**: los datos que se transmiten, normalmente un evento (`order.created`) con su carga útil.
* **Publisher**: el productor. Solo conoce el topic al que publica.
* **Topic** (o canal): el nombre que conecta a ambos lados. En la práctica lo gestiona un **broker**.
* **Subscriber**: el consumidor. Declara qué topics le interesan y qué hace con cada mensaje.
* **Broker**: el intermediario que recibe, enruta y entrega. En la figura son los carriles y las prensas.

***

## Un broker mínimo en TypeScript

Para entender el mecanismo no hace falta ninguna infraestructura. Este broker en memoria hace lo mismo que la figura:

<Code
  language="typescript"
  filename="broker.ts"
  code="type Handler<T> = (message: T) => void;

class Broker {
  private topics = new Map<string, Set<Handler<any>>>();

  subscribe<T>(topic: string, handler: Handler<T>) {
    const handlers = this.topics.get(topic) ?? new Set<Handler<any>>();
    handlers.add(handler);
    this.topics.set(topic, handlers);
    // Devolvemos la función para darse de baja
    return () => handlers.delete(handler);
  }

  publish<T>(topic: string, message: T) {
    // Si no hay suscriptores, el bucle no hace nada: el mensaje se pierde
    for (const handler of this.topics.get(topic) ?? []) handler(message);
  }
}"
/>

Y así se usa. Fíjate en que el código que publica no importa ni conoce a ningún consumidor:

<Code
  language="typescript"
  filename="uso.ts"
  code="const broker = new Broker();

const stopEmail = broker.subscribe('orders', (order) => sendConfirmation(order));
broker.subscribe('orders', (order) => reserveStock(order));

broker.publish('orders', { id: 42, total: 59.9 }); // llega a los dos

stopEmail(); // el servicio de correos se da de baja
broker.publish('orders', { id: 43, total: 12 }); // solo llega a stock"
/>

<Callout theme="warning" text="Este broker corre dentro de un único proceso y no guarda nada: si el proceso se cae, se pierden los mensajes. Sirve para entender el patrón o para eventos dentro de una misma aplicación, no para comunicar servicios distintos." />

***

## En producción: usa un broker de verdad

Cuando publisher y subscribers viven en servicios distintos, el broker es un sistema aparte que gestiona entrega, reintentos y persistencia. Opciones habituales: **Google Cloud Pub/Sub**, **Apache Kafka**, **RabbitMQ**, **Amazon SNS/SQS** o **Redis Pub/Sub** para casos más sencillos.

En Google Cloud Pub/Sub, el equivalente de la figura se arma así: un topic y una **suscripción** por cada servicio interesado.

<Code
  language="bash"
  filename="terminal"
  code="# El topic (el carril)
gcloud pubsub topics create orders

# Una suscripción por cada servicio (las prensas y bandejas)
gcloud pubsub subscriptions create email-service --topic=orders
gcloud pubsub subscriptions create stock-service --topic=orders

# Publicar un mensaje
gcloud pubsub topics publish orders --message='{\"orderId\": 42}'

# Cada suscripción recibe su propia copia
gcloud pubsub subscriptions pull email-service --auto-ack
gcloud pubsub subscriptions pull stock-service --auto-ack"
/>

Dos detalles que conectan con la figura. Cada suscripción recibe **su copia** del mensaje, y un topic sin suscripciones **no guarda los mensajes por defecto**: lo que publiques mientras nadie escucha se descarta, como en el desagüe.

***

## Lo que el patrón no te regala

Pub/sub desacopla, pero a cambio hay que tener en cuenta varias cosas:

* **Entrega al menos una vez.** La mayoría de los brokers pueden entregar un mensaje más de una vez (por ejemplo, tras un reintento). Los subscribers deben ser **idempotentes**: procesar dos veces el mismo mensaje no debe cobrar dos veces ni enviar dos correos.
* **El orden no suele estar garantizado.** Dos mensajes publicados seguidos pueden llegar en orden distinto. Si importa, hay que usar mecanismos específicos del broker (claves de ordenación o particiones).
* **Es asíncrono.** El publisher no recibe respuesta. Si necesitas saber que algo se procesó, hace falta otro mecanismo (otro evento de vuelta, por ejemplo).
* **Más difícil de depurar.** Seguir un flujo que pasa por varios subscribers exige trazas y un identificador de correlación en cada mensaje.
* **Los mensajes que fallan necesitan un destino.** Lo habitual es una **dead-letter queue**: tras varios intentos fallidos, el mensaje se aparta para revisarlo en vez de bloquear a los demás.

***

## ¿Cuándo usarlo y cuándo no?

<Accordion
  items={[
    {
      question: "¿Cuándo conviene pub/sub?",
      answer:
        "Cuando un mismo evento interesa a varios consumidores, cuando quieres poder agregar consumidores sin tocar al productor, o cuando el trabajo de los consumidores puede hacerse después sin que el usuario espere: correos, analítica, sincronización con otros sistemas, notificaciones.",
    },
    {
      question: "¿Cuándo NO conviene?",
      answer:
        "Cuando necesitas una respuesta inmediata del otro servicio (una petición y su respuesta: usa una llamada directa), cuando el flujo es simple y tiene un solo consumidor, o cuando necesitas una transacción que abarque todos los pasos y se deshaga por completo si uno falla.",
    },
    {
      question: "¿Es lo mismo que una cola de mensajes?",
      answer:
        "No. En una cola, cada mensaje lo procesa un solo consumidor del grupo (reparto de trabajo). En pub/sub, cada suscripción recibe una copia (difusión). Muchos brokers combinan ambos: varias suscripciones, y dentro de cada una, varios consumidores que se reparten el trabajo.",
    },
  ]}
/>

***

<Quiz
  title="Comprueba lo aprendido"
  questions={[
    {
      question: "Un publisher publica un mensaje en un topic con tres suscripciones. ¿Qué ocurre?",
      options: [
        { text: "Solo la primera suscripción lo recibe", correct: false },
        { text: "Cada suscripción recibe su propia copia", correct: true },
        { text: "El publisher espera la respuesta de las tres", correct: false },
      ],
      explanation: "En pub/sub cada suscripción recibe una copia del mensaje, y el publisher no espera respuesta ni sabe cuántas hay.",
    },
    {
      question: "Quieres agregar un servicio antifraude que reaccione a cada pedido. ¿Qué cambia en el servicio de pedidos?",
      options: [
        { text: "Hay que llamar al nuevo servicio desde el código de pedidos", correct: false },
        { text: "Nada: el nuevo servicio se suscribe al topic", correct: true },
        { text: "Hay que crear un topic distinto para cada consumidor", correct: false },
      ],
      explanation: "Es el desacople del patrón: el publisher no conoce a sus consumidores, así que agregar uno nuevo no lo toca.",
    },
    {
      question: "¿Por qué los subscribers deben ser idempotentes?",
      options: [
        { text: "Porque el broker puede entregar un mismo mensaje más de una vez", correct: true },
        { text: "Porque los mensajes siempre llegan desordenados", correct: false },
        { text: "Porque el publisher reenvía todo cada minuto", correct: false },
      ],
      explanation: "Con entrega al menos una vez, un reintento puede duplicar el mensaje. Procesarlo dos veces no debe tener efectos duplicados.",
    },
  ]}
/>

***

## Resumen

Pub/sub separa **quién produce** de **quién consume** a través de un topic. A cambio de renunciar a la respuesta inmediata y de diseñar con duplicados y orden en mente, ganas servicios que evolucionan por separado y consumidores que se suman sin tocar al productor. Si quieres repasar la infraestructura sobre la que corre en Google Cloud, empieza por la serie **Introducción a GCP**.

Comentarios

Inicia sesión para dejar un comentario.

Todavía no hay comentarios. ¡Sé el primero!