انتقل إلى المحتوى
use-cases / daily-digest-fan-out / hero
CRON · EXEC · PIPE FAN-OUT

ملخّص مجدول يتفرّع إلى 200 صندوق بريد

كل إثنين في الساعة 9 صباحاً، مدخل cron واحد يوقظ حاوية واحدة. السكربت يُصيّر الملخّص مرّة واحدة ويكتبه إلى رابط pipe بـ ?n=200. مئتا حلقة curl — واحدة لكل مشترك — تسحب البايتات نفسها بالتوازي وتُسلّمها إلى SMTP. التفرّع يعيش في الطبقة التحتيّة، لا في كودك.

اقرأ توثيق cron
use-cases / daily-digest-fan-out / mechanism

cron، exec، pipe — ثلاثة استدعاءات وانتهيت

Hoody Cron API يُسقط سطر crontab من 5 حقول في مدخل مُدار. السطر يشغّل سكربت exec يُصيّر الملخّص مرّة ويدفعه إلى مسار pipe بـ n=200. مئتا حلقة مشترك تسحب المسار ذاته بالتوازي — الخادم لا يحتفظ بشيء، والقارئ البطيء لا يستطيع حجب البقيّة.

cron · entries
POST · schedule
# Monday 09:00 — managed cron entryPOST /users/root/entries# الجسم المرسل إلى /users/root/entries{schedule: "0 9 * * 1",command: "bash /scripts/digest.sh"}
exec · digest.sh
PUT · sender
# Render once — markdown → HTMLdigest=$(render-digest.py)# ادفع البايتات إلى مسار الأنبوبecho "$digest" | curl -T - https://pipe.hoody.com/api/v1/pipe/digest-monday?n=200# Pipe blocks until 200 receivers connect, then streams
pipe · subscribers
GET · receivers
# 200 حلقة curl خفيفة، واحدة لكل مشتركwhile read addr; docurl -s https://pipe.hoody.com/api/v1/pipe/digest-monday?n=200 \| smtp-send "$addr" &done < subscribers.txt# الكل 200 بثت بالتوازي — الضغط العكسي يتعامل مع الفعل البطيء[INFO] Transfer complete.

cron لم يصبح أعقد. التفرّع انتقل إلى الطبقة التحتيّة — pipe لا يحتفظ بشيء، السكربت يُصيّر مرّة، والحلقة هي مجرّد SMTP عند الحافّة. لا قائمة انتظار، لا جدول إعادات، لا مقعد أداة حملات.

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

لماذا يتفوّق تفرّع HTTP على تفرّع SMTP

التصميم الساذج يكرّر 200 إرسال SMTP بالتسلسل، يستغرق 11 دقيقة، ويُسلّم مرّتين حين ينهار في المنتصف. شكل pipe يمنحك التوازي والإيدمبوتنسي وحاوية أصغر — مجّاناً.

PARALLELISM

مئتا متلقٍّ، تصيير واحد

الملخّص يُبنى مرّة واحدة بالضبط. مئتا حلقة curl تسحب البايتات نفسها في الوقت ذاته. تشغيل 4 ثوانٍ يحلّ محلّ حلقة تسلسليّة 11 دقيقة — pipe يطبّق الضغط العكسيّ على القرّاء البطيئين دون حجب البقيّة.

IDEMPOTENCY

لا انهيار في وسط الطيران لتنظيفه

لا توجد جدول حالة حملة لاستشارته. إن مات التشغيل قبل اتّصال الـ 200 جميعاً، فإن TTL الـ pipe يُخلي النصف غير المنتهي وتُعيد نقرة cron التالية التصيير. لا تسليم مزدوج، لا دفعة نصف-مرسَلة لتسويتها.

ECONOMICS

حاوية واحدة، 23 ساعة نائمة

السكربت يستيقظ مرّة في الأسبوع، يعمل أربع ثوانٍ، وتعود الحاوية إلى السكون. أنت تدفع لأربع ثوانٍ — لا لخدمة حملات تعمل دائماً، لا لفاتورة SES لكل متلقٍّ، لا لمقعد Mailchimp.

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

ما يتغيّر حين يتولّى السلك التفرّع

الـ 200 متلقٍّ ذاتهم، جسم الملخّص ذاته. شكل التشغيل هو ما يتحرّك — من دقائق-من-SMTP-التسلسليّ إلى ثوانٍ-من-HTTP-المتوازي.

  1. RUN DURATION4.2s

    وقت ساعة الحائط من نقرة cron إلى آخر تسليم. pipe يبثّ إلى الـ 200 جميعاً بالتوازي؛ عنق الزجاجة يصبح SMTP لأبطأ مشترك، لا الحلقة.

  2. RENDER COUNT

    جسم الملخّص يُحسب مرّة واحدة. pipe يُمرّر البايتات نفسها إلى كل متلقٍّ — لا إعادة تصيير قالب لكل متلقٍّ، لا فوترة لكل متلقٍّ، لا ذاكرة تخزين مؤقّت لكل متلقٍّ.

  3. RECEIVERS PER PATH200

    Hoody Pipe API يحدّ n عند 256. ملخّص أسبوعيّ بـ 200 يقع تحت السقف بأريحية — والقارئ البطيء يطبّق ضغطاً عكسياً لكنّه لا يحجب الآخرين.

حدود وفق Hoody Pipe API: عدد المتلقّين 1–256، TTL الـ pipe 5 دقائق في انتظار الاتّصالات، 1000 نقل نشط على مستوى الخادم. مدخل cron نفسه هو صفّ واحد في /users/root/entries بـ schedule وcommand وexpires_at اختياريّ.

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

كيف ينكشف التشغيل، الإثنين في 9 صباحاً

أربع لحظات. كل واحدة استدعاء HTTP واحد كنتَ ستفعله يدوياً. cron هو ساعة المنبّه؛ exec هو المُصيِّر؛ pipe هو السلك؛ الحلقة هي الشيء الوحيد الذي يكتبه الوكيل.

    01
    09:00:00

    نقرة cron

    المدخل المُدار على /users/root/entries ينطلق. الجدول: 0 9 * * 1. الأمر: bash /scripts/digest.sh. crontab نفسه هو سجلّ JSON واحد — لا Airflow DAG، لا خدمة سير عمل.

    02
    09:00:00

    تصيير مرّة

    سكربت exec يسحب بيانات الأسبوع، يُصيّر markdown، يُحوّل إلى HTML، ويكتب الجسم إلى stdout. تصيير واحد، حمولة واحدة — لا حلقة دمج بريديّ لكل متلقٍّ.

    03
    09:00:00

    PUT pipe ?n=200

    السكربت يُمرّر stdout عبر curl -T - إلى pipe/digest-monday?n=200. pipe يحتفظ بالرفع حتى يتّصل 200 متلقٍّ، ثم يبثّ الجسم إليهم جميعاً بالتوازي.

    04
    09:00:04

    200 SMTPs

    مئتا حلقة تستدعي curl على المسار ذاته وتُسلّم الجسم إلى SMTP الخاصّ بمشتركيها. البطيئة تحصل على ضغط عكسيّ. السريعة تنتهي في ميلّي ثوانٍ. التشغيل كلّه ينتهي في ثوانٍ.

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

مدخل cron واحد، حاوية واحدة، مئتا متلقٍّ.

الطريقة التي اعتدتَ فعلها بهاالطريقة التي تفعلها بها الطبقة التحتيّة
BEFORE · SERIAL SMTP WORKERfor sub in 200: smtp.send(render(sub))11 دقيقة · نصف-مُسلَّم عند الانهيار · فاتورة لكل متلقٍّ
بعد · مسار أنبوب واحدrender | curl -T - pipe/digest?n=2004 ثوانٍ · إيدمبوتنت · فاتورة إيقاظ واحدة
اقرأ مواصفات pipe
use-cases / daily-digest-fan-out / replaces

ما يحلّ هذا محلّه

الأدوات المعتادة حين تريد إرسال البريد ذاته إلى قائمة. كلّ منها يفرض عليك مستوى خدمة لما هو، في النهاية، تصيير واحد وحلقة HTTP تتفرّع.

  • SendGrid scheduled campaignsتسعير لكل بريد لحمولة أنتجها سكربتك أصلاً
  • Mailchimp daily digestsواجهة حملات كاملة ومقعد جمهور لإرسال أسبوعيّ واحد
  • Custom mail-merge cron jobsحلقة تسلسليّة وجدول إعادات وتشريح دفعة نصف-مرسَلة
  • AWS SES + Lambda scheduled batchقائمة انتظار وعامل ودور IAM وتنبيه CloudWatch لرعايته
  • Resend مع استدعاءات API مجمعةإنفاق API لكل متلقٍّ لجسم لم يتغيّر بين الإرسالات
  • Customer.io drip campaignsمحرّك تجزئة لقائمة تحتفظ بها أصلاً في ملفّ نصّيّ
use-cases / daily-digest-fan-out / cta

الإثنين في 9 كان يعني عاملاً يطحن عبر SMTP. الآن يعني نقرة cron واحدة، حاوية واحدة، وpipe يفعل البقيّة.

اقرأ دليل cron
use-cases / daily-digest-fan-out / related

اقرأ الآخرين