Zum Inhalt springen
use-cases / daily-digest-fan-out / hero
CRON · EXEC · PIPE FAN-OUT

Ein geplanter Digest, der an 200 Postfächer fan-outet

Jeden Montag um 9 Uhr weckt ein Cron-Eintrag einen einzelnen Container. Das Skript rendert den Digest einmal und schreibt ihn auf eine Pipe-URL mit ?n=200. 200 Curl-Loops — einer pro Subscriber — ziehen dieselben Bytes parallel und übergeben sie an SMTP. Das Fan-out lebt im Substrat, nicht in deinem Code.

Cron-Docs lesen
use-cases / daily-digest-fan-out / mechanism

Cron, Exec, Pipe — drei Calls und du bist fertig

Die Hoody Cron API droppt eine 5-Feld-Crontab-Zeile in einen Managed Entry. Die Zeile führt ein Exec-Skript aus, das den Digest einmal rendert und ihn auf einen Pipe-Pfad mit n=200 schiebt. 200 Subscriber-Loops ziehen denselben Pfad parallel — der Server hält nichts, und ein langsamer Reader kann den Rest nicht blockieren.

cron · entries
POST · schedule
# Montag 09:00 — Managed Cron-EintragPOST /users/root/entries# Body, der an /users/root/entries gesendet wird{schedule: "0 9 * * 1",command: "bash /scripts/digest.sh"}
exec · digest.sh
PUT · Sender
# Einmal rendern — Markdown → HTMLdigest=$(render-digest.py)# Die Bytes auf den Pipe-Pfad schiebenecho "$digest" | curl -T - https://pipe.hoody.com/api/v1/pipe/digest-monday?n=200# Pipe blockiert, bis 200 Receiver verbinden, dann streamt sie
pipe · subscribers
GET · Receiver
# 200 leichtgewichtige Curl-Loops, einer pro Subscriberwhile read addr; docurl -s https://pipe.hoody.com/api/v1/pipe/digest-monday?n=200 \| smtp-send "$addr" &done < subscribers.txt# Alle 200 parallel gestreamt — Backpressure regelt die langsamen[INFO] Transfer complete.

Der Cron wurde nicht komplexer. Das Fan-out wurde ins Substrat verlegt — die Pipe hält nichts, das Skript rendert einmal, und der Loop ist nur SMTP an der Edge. Keine Queue, keine Retry-Tabelle, kein Campaign-Tool-Seat.

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

Warum HTTP-Fan-out SMTP-Fan-out schlägt

Das naive Design loopt 200 SMTP-Sends seriell, dauert 11 Minuten und liefert doppelt aus, wenn es auf halber Strecke crasht. Die Pipe-Form gibt dir Parallelität, Idempotenz und einen kleineren Container — gratis.

PARALLELISM

Zweihundert Receiver, ein Render

Der Digest wird genau einmal gebaut. 200 Curl-Loops ziehen dieselben Bytes simultan. Ein 4-Sekunden-Lauf ersetzt einen 11-Minuten-Serial-Loop — die Pipe wendet Backpressure auf langsame Reader an, ohne den Rest zu blockieren.

IDEMPOTENCY

Kein Mid-Flight-Crash zum Aufräumen

Es gibt keine Campaign-State-Tabelle zu konsultieren. Wenn der Lauf stirbt, bevor alle 200 verbinden, evict die Pipe-TTL die unfertige Hälfte und der nächste Cron-Tick rendert neu. Keine Doppelzustellung, kein halb-gesendeter Batch zum Versöhnen.

ECONOMICS

Ein Container, 23 Stunden schlafend

Das Skript wacht einmal pro Woche auf, läuft vier Sekunden, und der Container geht zurück in Idle. Du zahlst für die vier Sekunden — nicht für einen Always-on-Campaign-Service, nicht für eine Per-Recipient-SES-Rechnung, nicht für einen Mailchimp-Seat.

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

Was sich ändert, wenn die Wire das Fan-out macht

Gleiche 200 Empfänger, gleicher Digest-Body. Die Form des Laufs ist das, was sich bewegt — von Minuten-of-Serial-SMTP zu Sekunden-of-Parallel-HTTP.

  1. LAUFDAUER4.2s

    Wall-Clock-Zeit von Cron-Tick bis zur letzten Zustellung. Die Pipe streamt parallel an alle 200 Receiver; der Bottleneck wird zum SMTP des langsamsten Subscribers, nicht zum Loop.

  2. RENDER-COUNT

    Der Digest-Body wird einmal berechnet. Die Pipe forwardet dieselben Bytes an jeden Receiver — kein Template-Re-Render pro Empfänger, kein Per-Recipient-Billing, kein Per-Recipient-Cache.

  3. RECEIVER PRO PFAD200

    Die Hoody Pipe API capt n bei 256. Ein wöchentlicher Digest mit 200 sitzt komfortabel unter der Decke — und ein langsamer Reader wendet Backpressure an, blockiert aber die anderen nicht.

Limits gemäß Hoody Pipe API: Receiver-Anzahl 1–256, 5-Minuten-Pipe-TTL für das Warten auf Verbindungen, 1000 aktive Transfers serverweit. Der Cron-Eintrag selbst ist eine Zeile in /users/root/entries mit schedule, command und einem optionalen expires_at.

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

Wie der Lauf abläuft, Montag um 9 Uhr

Vier Momente. Jeder davon ist ein einzelner HTTP-Call, den du von Hand machen würdest. Cron ist der Wecker; Exec ist der Renderer; Pipe ist die Wire; der Loop ist das Einzige, was der Agent schreibt.

    01
    09:00:00

    Cron-Tick

    Der Managed Entry auf /users/root/entries feuert. Schedule: 0 9 * * 1. Command: bash /scripts/digest.sh. Die Crontab selbst ist ein einzelner JSON-Record — kein Airflow-DAG, kein Workflow-Service.

    02
    09:00:00

    Einmal rendern

    Das Exec-Skript zieht die Daten der Woche, rendert das Markdown, konvertiert zu HTML und schreibt den Body auf stdout. Ein Render, ein Payload — kein Per-Recipient-Mail-Merge-Loop.

    03
    09:00:00

    PUT pipe ?n=200

    Das Skript pipet stdout in curl -T - gegen pipe/digest-monday?n=200. Die Pipe hält den Upload, bis 200 Receiver verbinden, dann streamt sie den Body parallel an alle.

    04
    09:00:04

    200 SMTPs

    200 Loops curlen denselben Pfad und übergeben den Body an das SMTP ihres Subscribers. Die langsamen bekommen Backpressure. Die schnellen sind in Millisekunden fertig. Der ganze Lauf ist in Sekunden vorbei.

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

Ein Cron-Eintrag, ein Container, 200 Empfänger.

wie du es früher gemacht hastwie das Substrat es macht
VORHER · SERIELLER SMTP-WORKERfor sub in 200: smtp.send(render(sub))11 Minuten · halb-zugestellt bei Crash · Per-Recipient-Bill
NACHHER · EIN PIPE-PFADrender | curl -T - pipe/digest?n=2004 Sekunden · idempotent · One-Wake-up-Bill
Pipe-Spec lesen
use-cases / daily-digest-fan-out / replaces

Was das ersetzt

Die Standard-Greift-Tools, wenn du dieselbe Email an eine Liste senden willst. Jedes davon stellt dir eine Service-Stufe in Rechnung für das, was am Ende ein Render und ein Fan-out-HTTP-Loop ist.

  • SendGrid Scheduled CampaignsPer-Email-Pricing für ein Payload, das dein Skript ohnehin produziert hat
  • Mailchimp Daily DigestsEine ganze Campaign-UI und ein Audience-Seat für einen wöchentlichen Send
  • Custom Mail-Merge-Cron-JobsEin serieller Loop, eine Retry-Tabelle und ein Halb-gesendeter-Batch-Postmortem
  • AWS SES + Lambda Scheduled BatchEine Queue, ein Worker, eine IAM-Rolle und ein CloudWatch-Alarm zum Babysitten
  • Resend mit gebatchten API-CallsPer-Recipient-API-Spend für einen Body, der sich zwischen Sends nicht geändert hat
  • Customer.io Drip-CampaignsEine Segmentation-Engine für eine Liste, die du ohnehin in einer Text-Datei führst
use-cases / daily-digest-fan-out / cta

Montag um 9 hieß früher: ein Worker, der sich durch SMTP grindet. Jetzt heißt es: ein Cron-Tick, ein Container und eine Pipe, die den Rest macht.

Cron-Guide lesen
use-cases / daily-digest-fan-out / related

Lies die anderen