Pular para o conteúdo
use-cases / daily-digest-fan-out / hero
CRON · EXEC · FAN-OUT DE PIPE

Um digest agendado que faz fan-out para 200 caixas de entrada

Toda segunda às 9h, uma entrada de cron acorda um único contêiner. O script renderiza o digest uma vez e o escreve numa URL de pipe com ?n=200. Duzentos loops curl — um por assinante — puxam os mesmos bytes em paralelo e os entregam ao SMTP. O fan-out vive no substrato, não no seu código.

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

Cron, exec, pipe — três chamadas e está pronto

A Hoody Cron API solta uma linha de crontab de 5 campos numa entrada gerenciada. A linha roda um script exec que renderiza o digest uma vez e o empurra num caminho de pipe com n=200. Duzentos loops de assinante puxam o mesmo caminho em paralelo — o servidor não segura nada, e um leitor lento não pode bloquear o resto.

cron · entries
POST · schedule
# Segunda 09:00 — entrada de cron gerenciadaPOST /users/root/entries# Body enviado a /users/root/entries{schedule: "0 9 * * 1",command: "bash /scripts/digest.sh"}
exec · digest.sh
PUT · enviador
# Renderiza uma vez — markdown → HTMLdigest=$(render-digest.py)# Empurra os bytes no caminho do pipeecho "$digest" | curl -T - https://pipe.hoody.com/api/v1/pipe/digest-monday?n=200# Pipe bloqueia até 200 receivers conectarem, depois faz streaming
pipe · assinantes
GET · receivers
# 200 loops curl leves, um por assinantewhile read addr; docurl -s https://pipe.hoody.com/api/v1/pipe/digest-monday?n=200 \| smtp-send "$addr" &done < subscribers.txt# Todos os 200 streamados em paralelo — backpressure cuida dos lentos[INFO] Transfer complete.

O cron não ficou mais complexo. O fan-out foi movido para o substrato — o pipe não segura nada, o script renderiza uma vez, e o loop é só SMTP na borda. Sem fila, sem tabela de retentativas, sem assento de ferramenta de campanha.

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

Por que fan-out HTTP bate fan-out SMTP

O design ingênuo faz loop em 200 envios SMTP em série, leva 11 minutos, e entrega em duplicidade quando crasha no meio. O formato de pipe te dá paralelismo, idempotência e um contêiner menor — de graça.

PARALELISMO

Duzentos receivers, um render

O digest é construído exatamente uma vez. Duzentos loops curl puxam os mesmos bytes simultaneamente. Uma rodada de 4 segundos substitui um loop serial de 11 minutos — o pipe aplica backpressure aos leitores lentos sem bloquear o resto.

IDEMPOTÊNCIA

Sem crash em pleno voo para limpar

Não há tabela de estado de campanha para consultar. Se a rodada morre antes dos 200 conectarem, o TTL do pipe expulsa a metade inacabada e o próximo tick do cron re-renderiza. Sem entrega dupla, sem batch meio-enviado para reconciliar.

ECONOMIA

Um contêiner, 23 horas dormindo

O script acorda uma vez por semana, roda quatro segundos, e o contêiner volta a ficar idle. Você paga pelos quatro segundos — não por um serviço de campanha sempre-ativo, não por uma fatura SES por destinatário, não por um assento Mailchimp.

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

O que muda quando o fio faz o fan-out

Mesmos 200 destinatários, mesmo body de digest. O formato da rodada é o que se move — de minutos-de-SMTP-serial para segundos-de-HTTP-paralelo.

  1. DURAÇÃO DA RODADA4,2s

    Tempo de relógio do tick do cron até a última entrega. O pipe faz streaming para todos os 200 receivers em paralelo; o gargalo vira o SMTP do assinante mais lento, não o loop.

  2. CONTAGEM DE RENDER

    O body do digest é computado uma vez. O pipe encaminha os mesmos bytes a cada receiver — sem re-render de template por destinatário, sem cobrança por destinatário, sem cache por destinatário.

  3. RECEIVERS POR CAMINHO200

    A Hoody Pipe API limita n a 256. Um digest semanal em 200 cabe confortavelmente abaixo do teto — e um leitor lento aplica backpressure mas não bloqueia os outros.

Limites pela Hoody Pipe API: contagem de receivers 1–256, TTL de 5 minutos esperando conexões, 1000 transferências ativas no servidor inteiro. A entrada de cron em si é uma linha em /users/root/entries com schedule, command e um expires_at opcional.

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

Como a rodada se desenrola, segunda às 9h

Quatro momentos. Cada um é uma única chamada HTTP que você faria à mão. Cron é o despertador; exec é o renderizador; pipe é o fio; o loop é a única coisa que o agente escreve.

    01
    09:00:00

    Tick do cron

    A entrada gerenciada em /users/root/entries dispara. Schedule: 0 9 * * 1. Command: bash /scripts/digest.sh. O crontab em si é um único registro JSON — não é um DAG do Airflow, não é um serviço de workflow.

    02
    09:00:00

    Renderiza uma vez

    O script exec puxa os dados da semana, renderiza o markdown, converte para HTML e escreve o body no stdout. Um render, um payload — sem loop de mail-merge por destinatário.

    03
    09:00:00

    PUT pipe ?n=200

    O script joga o stdout no curl -T - contra pipe/digest-monday?n=200. O pipe segura o upload até 200 receivers conectarem, depois faz streaming do body para todos eles em paralelo.

    04
    09:00:04

    200 SMTPs

    Duzentos loops fazem curl no mesmo caminho e entregam o body para o SMTP do seu assinante. Os lentos pegam backpressure. Os rápidos terminam em milissegundos. A rodada inteira acaba em segundos.

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

Uma entrada de cron, um contêiner, duzentos destinatários.

como você faziacomo o substrato faz
ANTES · WORKER SMTP SERIALfor sub in 200: smtp.send(render(sub))11 minutos · meio-entregue no crash · cobrança por destinatário
DEPOIS · UM CAMINHO DE PIPErender | curl -T - pipe/digest?n=2004 segundos · idempotente · uma fatura de wake-up
Ler a spec do pipe
use-cases / daily-digest-fan-out / replaces

O que isto substitui

As ferramentas padrão para quando você quer mandar o mesmo email para uma lista. Cada uma te cobra um tier de serviço pelo que é, no fim, um render e um loop HTTP de fan-out.

  • campanhas agendadas SendGridCobrança por email para um payload que seu script já produziu
  • digests diários MailchimpUma UI de campanha inteira e um assento de audiência para um envio semanal
  • Jobs cron customizados de mail-mergeUm loop serial, uma tabela de retentativas e um postmortem de batch meio-enviado
  • AWS SES + Lambda batch agendadoUma fila, um worker, um papel IAM e um alarme CloudWatch para babá
  • Resend com chamadas de API em batchGasto de API por destinatário para um body que não mudou entre envios
  • campanhas drip Customer.ioUm motor de segmentação para uma lista que você já guarda num arquivo de texto
use-cases / daily-digest-fan-out / cta

Segunda às 9 costumava significar um worker triturando SMTP. Agora significa um tick de cron, um contêiner, e um pipe que faz o resto.

Ler o guia do cron
use-cases / daily-digest-fan-out / related

Leia os outros