Ir al contenido
use-cases / daily-digest-fan-out / hero
CRON · EXEC · FAN-OUT POR PIPE

Un resumen programado que se reparte a 200 buzones

Cada lunes a las 9, una entrada de cron despierta un único contenedor. El script renderiza el resumen una vez y lo escribe a una URL de pipe con ?n=200. Doscientos bucles de curl — uno por suscriptor — tiran de los mismos bytes en paralelo y los entregan a SMTP. El fan-out vive en el sustrato, no en tu código.

use-cases / daily-digest-fan-out / mechanism

Cron, exec, pipe — tres llamadas y listo

La API de Hoody Cron suelta una línea de crontab de 5 campos en una entrada gestionada. La línea ejecuta un script exec que renderiza el resumen una vez y lo empuja a una ruta de pipe con n=200. Doscientos bucles de suscriptor tiran de la misma ruta en paralelo — el servidor no retiene nada, y un lector lento no puede bloquear al resto.

cron · entries
POST · schedule
# Lunes 09:00 — entrada cron gestionadaPOST /users/root/entries# Cuerpo enviado a /users/root/entries{schedule: "0 9 * * 1",command: "bash /scripts/digest.sh"}
exec · digest.sh
PUT · emisor
# Renderiza una vez — markdown → HTMLdigest=$(render-digest.py)# Empuja los bytes a la ruta del pipeecho "$digest" | curl -T - https://pipe.hoody.com/api/v1/pipe/digest-monday?n=200# El pipe bloquea hasta que se conectan 200 receptores, luego transmite
pipe · subscribers
GET · receptores
# 200 bucles ligeros de curl, uno por suscriptorwhile read addr; docurl -s https://pipe.hoody.com/api/v1/pipe/digest-monday?n=200 \| smtp-send "$addr" &done < subscribers.txt# Los 200 transmitidos en paralelo — la backpressure se ocupa de los lentos[INFO] Transfer complete.

El cron no se complicó más. El fan-out se movió al sustrato — el pipe no retiene nada, el script renderiza una vez y el bucle es solo SMTP en el borde. Sin cola, sin tabla de reintentos, sin asiento de herramienta de campañas.

use-cases / daily-digest-fan-out / powers

Por qué el fan-out HTTP gana al fan-out SMTP

El diseño naive recorre 200 envíos SMTP en serie, tarda 11 minutos y duplica entregas cuando se cae a mitad. La forma del pipe te da paralelismo, idempotencia y un contenedor más pequeño — gratis.

PARALELISMO

Doscientos receptores, un render

El resumen se construye exactamente una vez. Doscientos bucles de curl tiran de los mismos bytes simultáneamente. Una ejecución de 4 segundos reemplaza un bucle serial de 11 minutos — el pipe aplica backpressure a los lectores lentos sin bloquear al resto.

IDEMPOTENCIA

Sin caída a media ejecución que limpiar

No hay tabla de estado de campaña que consultar. Si la ejecución muere antes de que se conecten los 200, el TTL del pipe descarta la mitad sin terminar y el siguiente tick de cron re-renderiza. Sin entregas duplicadas, sin lote a medio enviar que reconciliar.

ECONOMÍA

Un contenedor, 23 horas dormido

El script despierta una vez por semana, corre cuatro segundos y el contenedor vuelve a inactivo. Pagas por los cuatro segundos — no por un servicio de campañas always-on, no por una factura de SES por destinatario, no por un asiento de Mailchimp.

use-cases / daily-digest-fan-out / timing

Lo que cambia cuando el cable hace el fan-out

Mismos 200 destinatarios, mismo cuerpo de resumen. Lo que se mueve es la forma de la ejecución — de minutos-de-SMTP-serial a segundos-de-HTTP-paralelo.

  1. DURACIÓN DE EJECUCIÓN4,2s

    Tiempo de reloj desde el tick del cron hasta la última entrega. El pipe transmite a los 200 receptores en paralelo; el cuello de botella se vuelve el SMTP del suscriptor más lento, no el bucle.

  2. RECUENTO DE RENDER

    El cuerpo del resumen se computa una vez. El pipe reenvía los mismos bytes a cada receptor — sin re-render de plantilla por destinatario, sin facturación por destinatario, sin caché por destinatario.

  3. RECEPTORES POR RUTA200

    La API de Hoody Pipe limita n a 256. Un resumen semanal a 200 entra cómodamente bajo el techo — y un lector lento aplica backpressure pero no bloquea a los demás.

Límites según la API de Hoody Pipe: receptores 1–256, TTL de pipe de 5 minutos esperando conexiones, 1000 transferencias activas en todo el servidor. La entrada de cron en sí es una fila en /users/root/entries con schedule, command y un expires_at opcional.

use-cases / daily-digest-fan-out / steps

Cómo se desarrolla la ejecución, lunes a las 9

Cuatro momentos. Cada uno es una llamada HTTP única que harías a mano. El cron es el despertador; exec es el renderizador; el pipe es el cable; el bucle es lo único que el agente escribe.

    01
    09:00:00

    Tick de cron

    La entrada gestionada en /users/root/entries se dispara. Schedule: 0 9 * * 1. Comando: bash /scripts/digest.sh. El crontab en sí es un único registro JSON — no un DAG de Airflow, no un servicio de workflows.

    02
    09:00:00

    Renderiza una vez

    El script exec tira de los datos de la semana, renderiza el markdown, convierte a HTML y escribe el cuerpo a stdout. Un render, un payload — sin bucle de mail-merge por destinatario.

    03
    09:00:00

    PUT pipe ?n=200

    El script tubería stdout a curl -T - contra pipe/digest-monday?n=200. El pipe retiene la subida hasta que se conectan 200 receptores, y luego transmite el cuerpo a todos en paralelo.

    04
    09:00:04

    200 SMTPs

    Doscientos bucles hacen curl a la misma ruta y entregan el cuerpo al SMTP de su suscriptor. Los lentos reciben backpressure. Los rápidos terminan en milisegundos. Toda la ejecución acaba en segundos.

use-cases / daily-digest-fan-out / punchline

Una entrada de cron, un contenedor, doscientos destinatarios.

como solías hacerlocomo lo hace el sustrato
ANTES · WORKER SMTP SERIALfor sub in 200: smtp.send(render(sub))11 minutos · medio entregado en caída · factura por destinatario
DESPUÉS · UNA RUTA DE PIPErender | curl -T - pipe/digest?n=2004 segundos · idempotente · una factura de despertar
use-cases / daily-digest-fan-out / replaces

Lo que esto reemplaza

Las herramientas estándar a las que recurres cuando quieres enviar el mismo email a una lista. Cada una te cobra un nivel de servicio por lo que es, al final, un render y un bucle HTTP de fan-out.

  • campañas programadas de SendGridPrecio por email para un payload que tu script ya produjo
  • resúmenes diarios de MailchimpToda una UI de campañas y un asiento de audiencia para un envío semanal
  • trabajos cron propios de mail-mergeUn bucle serial, una tabla de reintentos y un postmortem de lote a medio enviar
  • AWS SES + Lambda batch programadoUna cola, un worker, un rol IAM y una alarma de CloudWatch que vigilar
  • Resend con llamadas API en lotesGasto API por destinatario por un cuerpo que no cambió entre envíos
  • campañas drip de Customer.ioUn motor de segmentación para una lista que ya tienes en un archivo de texto
use-cases / daily-digest-fan-out / cta

Lunes a las 9 solía significar un worker moliendo SMTP. Ahora significa un tick de cron, un contenedor y un pipe que hace el resto.

Lee la guía de cron
use-cases / daily-digest-fan-out / related

Lee los otros