Cloudflare Dynamic Workflows: متى يستحق كل مسار سير عمل مستقلًا؟
متى يستحق مسار النشر سير عمل مستقلًا؟ تحليل عملي لـ Cloudflare Dynamic Workflows وحدود Workflows V2 وحماية idempotency عند تشغيل وكلاء الذكاء الاصطناعي.

لدي 6 عمليات نشر آلية تعمل من جهة Anthropic وتُطلق مهامها كل يوم، وكل واحدة منها ترسل طلب POST إلى PublishWorkflow ثابت واحد مفتاحه publish-{brief_id}. وفي 1 مايو أطلقت Cloudflare مشروع Cloudflare Dynamic Workflows عبر الحزمة @cloudflare/dynamic-workflows، ثم طرحت بعد بضعة أيام Workflows V2 بمستوى تحكم أعيد بناؤه ليتعامل مع الحمل الذي تطلقه الوكلاء. المهم هنا ليس خبر الإطلاق، بل أن اختياري سير عمل ثابتًا واحدًا لضمان ثبات النتيجة عند التكرار (idempotency) لم يعد قيدًا ورثته من المنصة؛ أصبح قرارًا عليّ الدفاع عنه.
ما الذي فاجأني فعلًا؟
كنت أتوقع إعلانًا خلاصته: «Workflows سيستوعب أحمالًا أكبر». حدود أعلى، وطابور أعمق، والزيادة السنوية المعتادة. لكن ذلك لم يكن سوى النصف الأقل أهمية.
أما التحول الحقيقي فهو أن شيفرة سير العمل باتت قابلة للاختلاف من مستأجر إلى آخر أثناء التشغيل. صدرت @cloudflare/dynamic-workflows في 1 مايو بترخيص MIT، وهي مبنية على Dynamic Workers. تتيح الحزمة تسجيل WorkflowEntrypoint واحد تُجلب شيفرته من Dynamic Worker عند إنشاء المثيل؛ وبذلك تتشكل بنية الخطوات وفق المستأجر بدل أن تُثبّت داخل عملية النشر. تصف Cloudflare الفكرة بأنها «تنفيذ دائم يتبع المستأجر»، وهي صياغة دقيقة جدًا لمن سبق له محاولة حشر منطق خاص بكل عميل داخل سير عمل واحد باستخدام feature flags.
عمليات النشر الست لدي — الأخبار، والتطوير، والبناء، والتصميم، والتسويق، والمؤسسون، والأعمال — تؤدي عمليًا دور 6 مستأجرين يتشاركون PublishWorkflow واحدًا. هي ليست عملاء، بل عمليات آلية مدعومة بالذكاء الاصطناعي تعمل من جهة Anthropic، وينتج كل منها مسارًا مختلفًا من المحتوى. ومع ذلك، ينطبق عليها نموذج البنية متعددة المستأجرين تمامًا: هيكل تنسيق واحد، واختلاف طفيف في شكل كل مسار، وكلها تُرسل إلى حساب Cloudflare نفسه.
ثم وصلت Workflows V2 بعد بضعة أيام، وكانت طريقة تقديمها أهم من أرقامها. فقد أُعيدت هندسة V2 صراحة على أساس أن الوكلاء ينشئون مثيلات سير العمل بسرعة الآلة، لا أن البشر ينشئونها بالنقر على أزرار. وهذا هو نمط التشغيل لدي حرفيًا: عندما تقرر عملية نشر طرح مقال، ينشئ حدث غير بشري مثيلًا لتنفيذ دائم. أما مستوى التحكم في V1 فقد صُمم لنمط حمل مختلف.
Dynamic Workflows: تنفيذ دائم يتبع المستأجر
إعلان Cloudflare عن @cloudflare/dynamic-workflows، وهي مكتبة بترخيص MIT مبنية على Dynamic Workers.
ماذا يعني ذلك للمؤسسين غير التقنيين؟
مصطلح «التنفيذ الدائم» يبدو وكأنه صيغ لإبعاد غير المتخصصين. معناه ببساطة: مهمة متعددة الخطوات تنجو من التعطل وتُستأنف من آخر خطوة مكتملة بدل أن تبدأ من الصفر. إذا تعطلت الخطوة 5 من أصل 8 لأن واجهة API توقفت، يعيد النظام محاولة الخطوة 5 وحدها؛ فلا يعيد تشغيل الخطوات من 1 إلى 4، ولا يحاسبك عليها مرة أخرى.
هذه هي النقطة التي تهم المؤسس. فالحد الفاصل لإعادة المحاولة عند كل خطوة هو نفسه الحد الفاصل لتكلفتها. إذا كان خط الإنتاج يستدعي نموذج ذكاء اصطناعي مدفوعًا في الخطوة 3 ونموذجًا مدفوعًا آخر في الخطوة 6، ثم تعطلت الخطوة 7، فالمراد هو إعادة الخطوة 7 لا المهمة كلها. وإعادة تشغيل خط إنتاج مدفوع من دون idempotency لا تعني صفًا مكررًا في قاعدة البيانات؛ بل فاتورة مكررة.
أما قرار البناء أو التأجيل الذي يمكن تلخيصه للمقاول في جملة واحدة فهو: افصل سير العمل لكل خط منتج فقط عندما يختلف منطق هذه الخطوط فعلًا، لا لمجرد أن المنصة أصبحت تتيح ذلك. لقد قدمت Cloudflare تجريدًا جديدًا قويًا، ومن السهل أن يدفع ذلك إلى إعادة التصميم حوله. لكن تكلفة N من تعريفات سير العمل تعني N أضعاف الصيانة، ولا تظهر الفائدة إلا حين تنفذ المسارات أعمالًا مختلفة حقًا. إذا سمع المؤسس اقتراحًا من نوع «لنمنح كل خط منتج سير عمل مستقلًا الآن بعد أن أصبح ذلك ممكنًا»، فعليه أن يسأل: ما الذي تغير في العمل نفسه، لا ما الذي تغير في المنصة؟
البنية التي أشغّلها فعليًا
البنية الحقيقية صغيرة بما يكفي لتصورها كاملة. تُنهي كل عملية نشر من جهة Anthropic بحثها، وتعد موجزًا، ثم ترسل طلب POST إلى /api/admin/publish في الموقع. تتحقق نقطة النهاية من الحمولة، وتنشئ معرّفًا للمثيل، ثم تستدعي instances.create على WorkflowEntrypoint واحد اسمه PublishWorkflow.
يتكون سير العمل نفسه من 8 مراحل step.do لا تتغير نتيجتها عند التكرار:
- التحقق (مخطط الموجز، وفرادة slug)
- الإسناد بالمصادر (جلب الاستشهادات، وحل الروابط)
- التوليد (استدعاء Claude لكتابة المحتوى)
- التنظيف (التحقق من توجيهات markdown)
- الحفظ (الإدراج في Postgres، وإدارة الإصدارات)
- الفهرسة (embeddings، وتحديث البحث)
- الغلاف (توليد الصورة ورفعها إلى R2)
- النشر (تغيير الحالة، وإرسال تنبيه sitemap)
export class PublishWorkflow extends WorkflowEntrypoint<Env, PublishParams> {
async run(event: WorkflowEvent<PublishParams>, step: WorkflowStep) {
const brief = await step.do("validate", () => validateBrief(event.payload));
const grounded = await step.do("ground", () => groundCitations(brief));
const draft = await step.do("generate", () => generateBody(grounded));
const cleaned = await step.do("clean", () => validateDirectives(draft));
const row = await step.do("persist", () => persistArticle(cleaned));
await step.do("index", () => reindex(row.id));
await step.do("cover", () => generateCover(row.id));
await step.do("publish", () => flipStatus(row.id));
}
}أما حد الإرسال فيبدو هكذا:
const id = `publish-${brief.brief_id}`;
try {
await env.PUBLISH.create({ id, params: brief });
} catch (e) {
if (isDuplicateIdError(e)) return new Response("already queued", { status: 200 });
throw e;
}يرفض instances.create معرّفًا مكررًا. ويؤدي هذا السطر الواحد عملًا جوهريًا: فهو وحده يمنع عملية نشر أعادت المحاولة من جهة Anthropic من نشر المقال نفسه مرتين ومحاسبتي مرتين على استدعاءات الذكاء الاصطناعي داخله.
لماذا أستخدم تعريفًا واحدًا لستة مسارات؟ لأن المراحل الثماني متطابقة في جميعها. الاختلاف محصور في حزمة التحرير — مواصفات النبرة والجمهور، وقائمة المحاذير، وإرشادات الموجز. تُرسل هذه العناصر كبيانات وقت التشغيل داخل حمولة الإرسال، لا كشيفرة. ويحدد اسم المسار الحزمة التي تصل إلى الخطوة 3 (generate)؛ أما بقية الخطوات فلا تعتمد على المسار.
موضع الضغط — والسبب الصادق الوحيد لفتح نقاش Dynamic Workflows أصلًا — هو أن أحد المسارات بدأ يحتاج إلى بنية خطوات مختلفة، لا إلى حزمة مختلفة فقط. فالمسار كثيف البحث يريد جولة إسناد إضافية قبل التوليد، وربما خطوة لتدقيق الحقائق بعده. هذا اختلاف بنيوي لا اختلاف في البيانات. حاليًا أنفذه كفرع شرطي داخل ground، وهو حل ناجح، لكنه من النوع الذي يتدهور سريعًا عندما تضيف 3 مسارات أخرى فروعها الاستثنائية الخاصة.
تكلفة الترحيل إلى Cloudflare Dynamic Workflows
هذه هي القيمة التي يقدمها createDynamicWorkflowEntrypoint: تُحمّل شيفرة سير عمل كل مسار وقت التشغيل من Dynamic Worker، ما يجعل تكلفة الاحتفاظ بالمسارات التي لم تعمل اليوم قريبة من الصفر. وتتوقف عن دفع ضريبة صيانة «جميع المسارات منشورة دائمًا داخل حزمة واحدة»، كما تستطيع تطوير شيفرة كل مسار بصورة مستقلة من دون إعادة نشر الهيكل المشترك.

أما التكلفة الصريحة فهي الجانب الذي لا تتوقف عنده تدوينة الإطلاق طويلًا. فأنت تستبدل WorkflowEntrypoint واحدًا يخضع لفحص الأنواع — وينبهك المترجم البرمجي عند تغير عقد مدخلات إحدى الخطوات — بعدد N من التعريفات المحمّلة وقت التشغيل، حيث يغيب هذا التنبيه. وهكذا يتحول انحراف عقود الخطوات بين المسارات من خطأ يظهر أثناء البناء إلى عطل في وقت التشغيل. إذا كانت لديك 6 مسارات وكانت خطوة persist تتوقع شكلًا مختلفًا قليلًا للصف في اثنين منها لأن أحدهم أعاد هيكلة نصف المسارات ونسي البقية، فلن تكتشف ذلك عند تشغيل CI، بل عندما يحاول مقال حقيقي أن يُنشر.
الترحيل ليس قرارًا بين الكل أو لا شيء؛ والتعامل معه بهذه الصورة هو أقصر طريق إلى الإفراط في الهندسة. خطتي هي:
- الإبقاء على الهيكل المشترك ذي المراحل الثماني في صورة
WorkflowEntrypointثابت. فهذا هو المسار التشغيلي الحرج، وتستخدمه 5 من المسارات الستة بلا تغيير. - بناء المسار كثيف البحث في صورة Dynamic Workflow ببنية خطواته الخاصة، بما فيها جولة إسناد إضافية وخطوة تدقيق الحقائق.
- اختيار الوجهة بحسب المسار عند حد
/publish، عبر تعليمة switch من سطر واحد علىbrief.laneتحدد أي binding سيُستدعى عليهcreate.
متى تحذف شيفرة Cloudflare Workflow: الوكلاء المُدارون والنتائج وwebhooks
القرار المعاكس: متى تجعل Anthropic Managed Agents سير عمل CF لديك زائدًا عن الحاجة؟
وقاعدة القرار، مع وضع رقم واضح لها، هي: لا تنقل مسارًا إلى Dynamic Workflow مستقل إلا عندما تختلف بنية خطواته عن الهيكل الأساسي بأكثر من مرحلة واحدة. تحت هذه العتبة، يكون الفرع الشرطي داخل الخطوة الحالية أقل كلفة في الصيانة من تعريف سير عمل ثانٍ. وفوقها تبدأ الفروع داخل الخطوة بحجب ما يفعله المسار، وعندئذ يبرر التعريف المنفصل تكلفته.
مسار واحد فوق العتبة، و5 مسارات تحتها. تلك هي خطة الترحيل في جملتين. ولو وصلني الموجز نفسه من مقاول يقترح تقسيم المسارات الستة كلها إلى Dynamic Workflows منذ اليوم الأول، فلن أوافق عليه. تكلفة البناء حقيقية، بينما تتركز الفائدة في مسار واحد بالضبط.
كيف تغير Cloudflare Workflows V2 سير عمل وكلاء الذكاء الاصطناعي؟
الأرقام البارزة في V2 هي 50,000 مثيل متزامن و2,000,000 مثيل في الطابور لكل سير عمل، بعد أن كان حد الطابور 1,000,000 في V1. ليست هذه أرقامًا استعراضية، لكنها بعيدة جدًا أيضًا عن نطاق عملي. فمع تشغيل 6 عمليات مرة أو مرتين يوميًا، أبقى أدنى من السقف الجديد بنحو 9 مراتب أسّية.
Cloudflare Workflows V2: إعادة تنفيذ حتمية و50k مثيل متزامن
تغطية InfoQ لإعادة هندسة مستوى التحكم في V2 وحدود التزامن الجديدة.
ما يهم في بنيتي ليس الأرقام، بل أن مستوى التحكم في V2 أُعيد بناؤه حول إنشاء المثيلات بواسطة الوكلاء بوصفه الحالة الأساسية. كان V1 محسّنًا للنمط الذي يبدأه الإنسان: ينقر المستخدم زرًا، فيبدأ مثيل، ويتعامل النظام مع حمل متقطع لكنه محدود. أما V2 فيفترض أن المحفز عملية آلية لا شخصًا، وأن المعدل تحدده قدرة الوكلاء في المنبع، لا نقرات واجهة المستخدم.
إعادة التنفيذ الحتمية هي الخاصية في V2 التي تستحق شرحًا مباشرًا. كل خطوة معزولة، وقابلة لإعادة التنفيذ، ولا تتغير نتيجتها عند التكرار، ويستأنف سير العمل من آخر خطوة ناجحة عند إعادة المحاولة. وهذه هي بالضبط الخاصية التي كان معرّف المثيل publish-{brief_id} يحميها يدويًا عند حد الإرسال. منحني V1 ضمان إعادة المحاولة لكل خطوة؛ أما V2 فيشدد دلالات إعادة التنفيذ، بحيث أصبحت الخاصية البنيوية التي كنت أحميها مفروضة أيضًا على مستوى المنصة الأساسية.
الخطوة العملية هذا الأسبوع: لا شيء في المسار التشغيلي الحرج. لا ينتقل النظام إلى نموذج V2 إلا بإعادة النشر، وأسوأ ما يمكن فعله بخط إنتاج سليم من ناحية idempotency هو نقله على عجل إلى مستوى تحكم جديد للحاق بدلالات يملكها أصلًا. سأنقل المسار كثيف البحث إلى V2 عندما أبنيه في صورة Dynamic Workflow، لأن وضع الشيفرة الجديدة على النموذج الجديد قليل الكلفة. أما المسارات الثابتة الخمسة فستبقى حيث هي إلى أن يظهر سبب للمساس بها غير أن «المنصة أطلقت إصدارًا جديدًا».
الثابت الوحيد الذي لن أتنازل عنه
استخدام publish-{brief_id} معرّفًا للمثيل ركيزة أساسية. إذا حُذف، فسيعيد خط الإنتاج التشغيل عندما تعيد إحدى عمليات Anthropic المحاولة من جهتها، وينشر المقال نفسه مرتين، وتتكرر كلفة كل استدعاء API مدفوع داخل سير العمل.
ضوابط وكلاء الذكاء الاصطناعي في الإنتاج: دليل الحد من نطاق الضرر
الخطوات ذات idempotency طبقة للحد من الضرر، ونقطة خنق التكلفة طبقة أخرى.
لا يهدد Dynamic Workflows هذا الثابت مباشرة؛ فعقد المعرّف في instances.create لم يتغير. الخطر المحتمل هو إعادة هيكلة مهملة لكل مسار، تبدأ معها شيفرة المسار باشتقاق المعرّف محليًا من جديد. قد يقرر مسار مثلًا إضافة طابع زمني إلى المعرّف «للاحتياط»، فيكسر إزالة التكرار بصمت لأن كل محاولة تولد عندئذ معرّفًا فريدًا.
والقاعدة التي تنجو من كل ترقية إصدار — والتي سأكتبها على الحائط قبل السماح لأي شخص آخر بلمس هذه الشيفرة — هي:
هذا النوع من الثوابت لا يظهر في تدوينة إطلاق أو دليل ترحيل، لأنه لا ينشأ إلا بعد معاناة العطل الذي يمنعه في الإنتاج. أما طبقة كبح التكلفة — أي ضمان ألا تتحول جولة واحدة من سير العمل إلى فاتورة منفلتة حتى لو فشلت إزالة التكرار — فهي منفصلة وتعيش عند مستوى استدعاء النموذج، لا مستوى المثيل. توجد الطبقتان للسبب نفسه: في خط إنتاج تكلّف كل خطوة فيه مالًا، تكون السلامة البنيوية أرخص تأمين يمكن شراؤه.
ما الذي كنت سأفعله بصورة مختلفة لو بدأت من الصفر في مايو 2026؟
لو بدأت بناء هذه المنظومة اليوم بدل أن أرث قرارات تعود إلى عام مضى، لغيّرت 3 أمور.
أولًا، كنت سأبدأ بهيكل ثابت مشترك مع Dynamic Workflow واحد لأي مسار مختلف حقًا، لا 6 تعريفات منفصلة. حين يصل تجريد جديد، يسهل الوقوع في إغراء استخدامه في كل مكان، لكن ضريبة صيانة N من تعريفات سير العمل تصل قبل فائدة التوسع. ستة تعريفات تعني 6 مواضع لإصلاح العطل، و6 مواضع لترقية تبعية برمجية، و6 مواضع يمكن أن ينحرف فيها عقد إحدى الخطوات. هيكل واحد مع حالة شاذة واحدة هو الحد الأدنى العملي للتقسيم.
ثانيًا، كنت سأضع مفتاح idempotency عند حد HTTP منذ اليوم الأول. إضافة publish-{brief_id} بعد واقعة نشر مزدوج هي الطريق المكلفة: يلزم تسوية الصفوف المنشورة مرتين، ورد المبالغ التي ترتبت عليها، وإضافة أدوات الرصد إلى طبقة الإرسال بينما تعمل المنظومة في الإنتاج. أما إضافة نمط try { create({id}) } catch (dup) {} قبل أن تنشر خط إنتاج أصلًا فلا تستغرق سوى 10 دقائق، وتمنع فئة كاملة من الأعطال.
ثالثًا، كنت سأتعامل مع حتمية Workflows V2 بوصفها الحد الأدنى للتصميم، لا ميزة أقرر تفعيلها لاحقًا. صمّم كل خطوة بحيث تكون آمنة عند إعادة التنفيذ حتى لو لم تقترب يومًا من سقف التزامن البالغ 50k. فالأمان عند إعادة التنفيذ ليس خاصية توسع، بل خاصية صحة. الخطوة غير الآمنة عند إعادة التنفيذ ستتعطل مع إعادة المحاولة، وإعادة المحاولة تحدث عند أي نطاق.
هذا هو قرار الخبير وإن بدا تقنيًا بحتًا. الفخ هو التعامل مع قدرات المنصة الجديدة كميزات ينبغي تبنيها. أما الانضباط فهو معاملتها كقيود يجب أن يصمم النظام على أساسها، سواء استُفيد من السعة الإضافية أم لا.
هل أحتاج إلى Dynamic Workflows إذا كان جميع المستأجرين ينفذون المنطق نفسه؟
لا. إذا كانت بنية الخطوات متطابقة ولا تختلف سوى البيانات، فأرسل البيانات ضمن حمولة الإرسال وأبقِ سير عمل ثابتًا واحدًا. تستحق Dynamic Workflows تكلفتها عندما تختلف الشيفرة نفسها لكل مستأجر — أي حين تختلف بنية الخطوات، لا المعاملات داخلها فحسب.
هل تعطل Workflows V2 مسارات العمل الحالية على V1؟
V2 مستوى تحكم أعيدت هندسته للتركيز على التنفيذ الحتمي الذي تطلقه الوكلاء. تعامل مع الترحيل بوصفه اختياريًا، وتحقق من idempotency قبل نقل مسار تشغيلي حرج، ولا تنقل شيفرة تعمل لمجرد ظهور إصدار جديد.
ما الحد الفعلي للتزامن الآن؟
50,000 مثيل متزامن و2,000,000 مثيل في الطابور لكل سير عمل، بعد أن كان حد الطابور 1,000,000. هذا أعلى كثيرًا من نطاق عمل معظم المشغلين، والخاصية الأهم في V2 هي إعادة التنفيذ الحتمية، لا السقف الجديد.
هل أصبحت @cloudflare/dynamic-workflows جاهزة للإنتاج أم ما زالت نسخة تجريبية؟
صدرت في 1 مايو 2026 كمكتبة بترخيص MIT مبنية على Dynamic Workers. اجعل نضج المكتبة وعقد idempotency لديك معيارَي حسم المخاطر، لا الترخيص. إذا كانت طبقة الإرسال سليمة، فستكون المكتبة جاهزة قبل خطة ترحيلك.
متى ينبغي للمؤسس أن يدفع لمهندس مقابل هذا الترحيل؟
عندما يختلف منطق الأتمتة في خط منتج عن بقية الخطوط اختلافًا حقيقيًا — بنية خطوات مختلفة، لا معاملات مختلفة. التقسيم من أجل التوسع وحده سابق لأوانه؛ أما اختلاف المنطق فهو المحفز الفعلي. وإذا كان فريقك يحتاج إلى مساعدة في حساب جدوى ترحيل كهذا، فهذا بالضبط نوع المراجعة المعمارية التي أقدمها عبر DVNC.dev.
4 سبتمبر 2026







