Aller au contenu
TYPEDébloqué
ÉTAPEFlotte
DIFFICULTÉModéré
MÉTIERPartager un flux
POURÉquipes de devs
POURFondateurs solo
SERVICESCron
SERVICESExec
SERVICESPipe
POURQUOI HOODYHTTP-natif
POURQUOI HOODYÉconomie des conteneurs
TYPEDébloqué
ÉTAPEFlotte
DIFFICULTÉModéré
MÉTIERPartager un flux
POURÉquipes de devs
POURFondateurs solo
SERVICESCron
SERVICESExec
SERVICESPipe
POURQUOI HOODYHTTP-natif
POURQUOI HOODYÉconomie des conteneurs
TYPEDébloqué
ÉTAPEFlotte
DIFFICULTÉModéré
MÉTIERPartager un flux
POURÉquipes de devs
POURFondateurs solo
SERVICESCron
SERVICESExec
SERVICESPipe
POURQUOI HOODYHTTP-natif
POURQUOI HOODYÉconomie des conteneurs
TYPEDébloqué
ÉTAPEFlotte
DIFFICULTÉModéré
MÉTIERPartager un flux
POURÉquipes de devs
POURFondateurs solo
SERVICESCron
SERVICESExec
SERVICESPipe
POURQUOI HOODYHTTP-natif
POURQUOI HOODYÉconomie des conteneurs
CRON · EXEC · FAN-OUT PIPE

Un digest planifié qui se diffuse vers 200 boîtes mail

Chaque lundi à 9h, une seule entrée cron réveille un seul container. Le script rend le digest une fois et l'écrit sur une URL pipe avec ?n=200. Deux cents boucles curl — une par abonné — tirent les mêmes octets en parallèle et les passent à SMTP. Le fan-out vit dans le substrat, pas dans votre code.

Lire la doc cron

Cron, exec, pipe — trois appels et c'est terminé

La Hoody Cron API dépose une ligne crontab à 5 champs dans une entrée gérée. La ligne exécute un script qui rend le digest une fois et le pousse sur un chemin pipe avec n=200. Deux cents boucles d'abonnés tirent le même chemin en parallèle — le serveur ne retient rien, et un lecteur lent ne peut pas bloquer les autres.

cron · entries
POST · planification
# Lundi 09:00 — entrée cron géréePOST /users/root/entries# Body envoyé à /users/root/entries{schedule: "0 9 * * 1",command: "bash /scripts/digest.sh"}
exec · digest.sh
PUT · expéditeur
# Rends une fois — markdown → HTMLdigest=$(render-digest.py)# Pousse les octets sur le chemin pipeecho "$digest" | curl -T - https://pipe.hoody.com/api/v1/pipe/digest-monday?n=200# Le pipe bloque jusqu'à ce que 200 receivers se connectent, puis stream
pipe · abonnés
GET · receivers
# 200 boucles curl légères, une par abonnéwhile read addr; docurl -s https://pipe.hoody.com/api/v1/pipe/digest-monday?n=200 \| smtp-send "$addr" &done < subscribers.txt# Les 200 streamés en parallèle — la backpressure gère les lents[INFO] Transfert terminé.

Le cron n'est pas devenu plus complexe. Le fan-out a été déplacé dans le substrat — le pipe ne retient rien, le script rend une fois, et la boucle n'est que du SMTP en bord. Pas de queue, pas de table de retry, pas de siège dans un outil de campagne.

Pourquoi le fan-out HTTP bat le fan-out SMTP

Le design naïf boucle 200 envois SMTP en série, prend 11 minutes, et double-livre quand il crashe à mi-parcours. La forme pipe vous donne parallélisme, idempotence, et un conteneur plus petit — gratuitement.

PARALLÉLISME

Deux cents receivers, un seul rendu

Le digest est construit exactement une fois. Deux cents boucles curl tirent les mêmes octets simultanément. Un run de 4 secondes remplace une boucle série de 11 minutes — le pipe applique la backpressure aux lecteurs lents sans bloquer les autres.

IDEMPOTENCE

Pas de crash en plein vol à nettoyer

Il n'y a pas de table d'état de campagne à consulter. Si le run meurt avant que les 200 ne se connectent, le TTL du pipe évince la moitié non terminée et le prochain tick cron re-rend. Pas de double-livraison, pas de batch à moitié envoyé à réconcilier.

ÉCONOMIE

Un conteneur, 23 heures endormi

Le script se réveille une fois par semaine, tourne quatre secondes, et le conteneur retourne au repos. vous payez les quatre secondes — pas un service de campagne always-on, pas une facture SES par destinataire, pas un siège Mailchimp.

Ce qui change quand le câble fait le fan-out

Mêmes 200 destinataires, même corps de digest. C'est la forme du run qui bouge — de minutes-de-SMTP-en-série à secondes-de-HTTP-parallèle.

  1. DURÉE DU RUN4,2 s

    Temps mur du tick cron à la dernière livraison. Le pipe stream vers les 200 receivers en parallèle ; le frein devient le SMTP de l'abonné le plus lent, pas la boucle.

  2. NOMBRE DE RENDUS

    Le corps du digest est calculé une fois. Le pipe forwarde les mêmes octets vers chaque receiver — pas de re-rendu de template par destinataire, pas de facturation par destinataire, pas de cache par destinataire.

  3. RECEIVERS PAR CHEMIN200

    La Hoody Pipe API plafonne n à 256. Un digest hebdo à 200 reste confortablement sous la limite — et un lecteur lent applique la backpressure sans bloquer les autres.

Limites d'après la Hoody Pipe API : nombre de receivers 1–256, TTL pipe de 5 minutes en attente de connexions, 1000 transferts actifs côté serveur. L'entrée cron elle-même est une ligne dans /users/root/entries avec schedule, command, et un expires_at optionnel.

Comment le run se déroule, lundi à 9h

Quatre moments. Chacun est un seul appel HTTP que vous feriez à la main. Le cron est le réveil ; l'exec est le moteur de rendu ; le pipe est le câble ; la boucle est la seule chose que l'agent écrit.

    01
    09:00:00

    Tick cron

    L'entrée gérée sur /users/root/entries se déclenche. Schedule : 0 9 * * 1. Command : bash /scripts/digest.sh. Le crontab lui-même est un seul enregistrement JSON — pas un DAG Airflow, pas un service de workflow.

    02
    09:00:00

    Rendu unique

    Le script exec tire les données de la semaine, rend le markdown, le convertit en HTML, et écrit le corps sur stdout. Un rendu, un payload — pas de boucle de mail-merge par destinataire.

    03
    09:00:00

    PUT pipe ?n=200

    Le script pipe stdout dans curl -T - vers pipe/digest-monday?n=200. Le pipe retient l'upload jusqu'à ce que 200 receivers se connectent, puis stream le corps à tous en parallèle.

    04
    09:00:04

    200 SMTP

    Deux cents boucles curl le même chemin et passent le corps au SMTP de leur abonné. Les lents reçoivent de la backpressure. Les rapides finissent en millisecondes. Tout le run est terminé en quelques secondes.

Une entrée cron, un conteneur, deux cents destinataires.

comme vous le faisais avantcomme le substrat le fait
AVANT · WORKER SMTP EN SÉRIEfor sub in 200: smtp.send(render(sub))11 minutes · à moitié livré au crash · facture par destinataire
APRÈS · UN CHEMIN PIPErender | curl -T - pipe/digest?n=2004 secondes · idempotent · une facture par réveil
Lire la spec pipe

Ce que ça remplace

Les outils standards qu'on dégaine quand on veut envoyer le même mail à une liste. Chacun vous facture un palier de service pour ce qui est, au fond, un rendu et une boucle HTTP de fan-out.

  • campagnes planifiées SendGridTarif par mail pour un payload que votre script a déjà produit
  • digests quotidiens MailchimpToute une UI de campagne et un siège audience pour un envoi hebdo
  • jobs cron mail-merge maisonUne boucle série, une table de retry, et un postmortem batch à moitié envoyé
  • AWS SES + batch planifié LambdaUne queue, un worker, un rôle IAM, et une alarme CloudWatch à surveiller
  • Resend avec appels API batchésCoût API par destinataire pour un corps qui n'a pas changé entre les envois
  • campagnes drip Customer.ioUn moteur de segmentation pour une liste que vous gardez déjà dans un fichier texte

Lundi 9h, ça voulait dire un worker qui mouline du SMTP. Maintenant ça veut dire un tick cron, un conteneur, et un pipe qui fait le reste.

Lire le guide cron

Lis les autres