Skip to main content

من Digital FTE إلى عامل إنتاج: دورة مكثفة في 90 دقيقة

15 مفهوماً، نحو 80% من الاستخدام الحقيقي: التنفيذ المتين، المحفزات، والتحكم في التدفق

هذه دورة متابعة في مسار البرمجة الوكيلة. الدورة السابقة، من وكيل إلى Digital FTE، انتهت بعامل دعم عملاء: OpenAI Agents SDK، مهارات قابلة للنقل، Neon Postgres كمصدر حقيقة، وخادم MCP مخصص. ذلك العامل يعمل عندما تستدعيه أنت. أما عامل الإنتاج الحقيقي فلا ينتظر أن تكتب له في prompt.

الفكرة الواحدة التي تجعل كل شيء مفهوماً: تحويل Digital FTE إلى Production Worker يحتاج إضافة بنيوية واحدة: محرك تنفيذ متين يسمح للعالم باستدعاء العامل، وينجو من الأعطال وسط العمل، ويضبط معدله على نطاق الإنتاج. في هذه الدورة نستخدم Inngest. الأنماط تنتقل إلى Temporal أو Restate أو Dapr Agents، لكن Inngest يقدم مدخلاً عملياً وسريعاً.

بالعربية المبسطة: Digital FTE من الدورة السابقة دالة تستدعيها. Production Worker هو دالة يستدعيها العالم: cron، webhook، حدث من inbox، أو حدث من Worker آخر. وعندما يعمل، يعمل بمتانة: إذا تعطل منتصف عملية من ست خطوات، لا تضيع الخطوات الثلاث الأولى.

كيف تقرأ هذه الصفحة في المرور الأول

اقرأ المفاهيم الخمسة عشر أولاً لتفهم اللغة. لا تحاول بناء كل شيء في أول مرور. بعد ذلك انتقل إلى المثال العملي، واتبع القرارات بالترتيب. إذا كنت قائداً غير تقني، يكفي أن تفهم لماذا يحتاج العامل إلى غلاف تشغيلي قبل أن يصبح صالحاً للإنتاج.

مسرد سريع
  • Event: رسالة تقول إن شيئاً حدث.
  • Cron: محفز يعمل لأن الوقت مر.
  • Webhook: طلب من نظام خارجي.
  • Durable execution: تنفيذ يستطيع الاستئناف بعد عطل.
  • Memoization: حفظ نتيجة خطوة حتى لا تعاد بلا حاجة.
  • Replay: إعادة تشغيل حدث أو مسار لفحصه أو إصلاحه.
  • HITL: إنسان داخل الحلقة للموافقات المهمة.
Currency

الأمثلة الحالية تعكس حالة Inngest وinngest-py حتى مايو 2026. تحقق من الوثائق قبل استخدام API في إنتاج حقيقي.

اختر أداتك

يمكنك تنفيذ المختبر بـ Claude Code أو OpenCode. الفرق في السطح؛ قرارات البنية واحدة.

المكسب السريع في خمس عشرة دقيقة: شاهد المتانة بعينيك

اكتب دالة صغيرة تسجل خطواتها، ثم اجعل خطوة منها تفشل مرة وتنجح في الإعادة. الهدف أن ترى أن المنصة لا تعامل الدالة كطلب HTTP عادي يضيع عند الانقطاع.

# hello.py
def greet_customer(name: str) -> str:
return f"Hello, {name}"
# داخل greet_customer، استبدل خطوة واحدة بخطوة durable
farewell = await step.run("compose-farewell", lambda: "Thanks for writing in.")

الجزء 1: المحفزات، كيف يستدعي العالم العامل

Concept 1: الأحداث مقابل الطلبات

الطلب يعني أن المتصل ينتظر. الحدث يعني أن المتصل يطلق إشارة ويكمل. عمال الإنتاج يعيشون على الأحداث لأن العمل قد يطول أو ينتشر أو يحتاج انتظاراً.

# request: caller waits
result = handle_ticket(ticket_id)

# event: caller fires and returns
send_event("email.received", {"ticket_id": ticket_id})

Concept 2: محفزات cron

Cron مناسب للعمل الذي يحدث لأن الوقت مر: فحص صحة العملاء يومياً، تذكير أسبوعي، أو تنظيف شهري. لا تستخدم cron لتعويض غياب الأحداث إذا كان النظام يستطيع إرسال event حقيقي.

Concept 3: Webhook triggers

Webhook هو الباب الذي يدخل منه العالم الخارجي: Stripe، Gmail، GitHub، CRM. يحتاج توقيعاً أو تحققاً، ثم تحويل payload إلى event داخلي موحد.

Concept 4: Idempotency ومعاني الحدث

قد يصل الحدث مرتين. يجب أن يستطيع العامل تكرار المعالجة بلا ضرر. استخدم event id، وسجلات processed، وقيود قاعدة بيانات. Exactly-once شعار؛ عملياً تبني at-least-once مع idempotency.

Exactly-once عند الحدود الخارجية يحتاج طبقتين

محرك التنفيذ يحفظ خطواتك، لكنه لا يستطيع وحده منع بوابة دفع أو بريد خارجي من تنفيذ الفعل مرتين إذا لم تعطها مفتاح idempotency أو تسجل الحالة في قاعدة بياناتك.

Concept 5: Fan-out وتفويض وكلاء فرعيين

حدث واحد قد يطلق أعمالاً متعددة: تلخيص ticket، تحديث CRM، فحص سياسة refund، وإبلاغ مدير. fan-out يجعل كل فرع مستقلاً وقابلاً للإعادة.

الجزء 2: التنفيذ المتين، ماذا يحدث عند الكسر

Concept 6: step.run ونموذج الدوال المتينة

step.run يعلّم المنصة أن هذه خطوة مسماة. إذا نجحت، تحفظ نتيجتها. إذا تعطلت الدالة لاحقاً، لا تعاد الخطوة الناجحة بلا حاجة.

summary = await step.run(
"summarize-ticket",
lambda: support_agent.summarize(ticket)
)

Concept 7: Memoization تحت الاستئناف

الاستئناف ليس سحراً. المنصة تحفظ حدود الخطوات ونتائجها. لذلك سمّ الخطوات بأسماء مستقرة، ولا تجعل خطوة واحدة تحتوي نصف النظام. الخطوة الكبيرة تعيد الألم نفسه داخل صندوق أكبر.

Concept 8: step.sleep وstep.wait_for_event

العامل الإنتاجي ينتظر: يومين قبل المتابعة، أو حتى يوافق إنسان، أو حتى يصل webhook آخر. لا تستخدم time.sleep في عامل إنتاجي؛ استخدم انتظاراً durable.

await step.sleep("wait-two-days", "2d")
approval = await step.wait_for_event("approval.received", timeout="7d")

Concept 9: retries وdead-letter

الفشل المؤقت يعاد. الفشل الدائم يحتاج dead-letter أو issue بشري. لا تجعل retry يخفي bug لا نهاية له. عرّف عدد المحاولات، backoff، وماذا يحدث بعد الفشل النهائي.

Concept 10: step.run لاستدعاءات الذكاء الاصطناعي في Python

في Python، لف استدعاء النموذج داخل step.run. بعض helpers موجودة في TypeScript فقط؛ الفكرة ليست اسم helper بل حفظ حدود الاستدعاء ونتيجته.

إذا كنت تلف Worker يستخدم DeepSeek

تأكد أن إعداد base URL والنموذج يحدث داخل طبقة واحدة واضحة، وأن trace لا يسجل بيانات عملاء حساسة بلا قصد.

الجزء 3: التحكم في التدفق والتعافي على نطاق الإنتاج

Concept 11: التزامن والخنق

إذا وصلت 500 رسالة في دقيقة، لا يعني ذلك تشغيل 500 استدعاء نموذج فوراً. ضع حدود concurrency، ومعدلات لكل عميل، وحماية connection pool.

Concept 12: الأولوية والإنصاف

Multi-tenant production يعني أن عميلًا واحداً لا يجب أن يبطئ الجميع. ضع queues أو مفاتيح concurrency بحسب tenant أو نوع المهمة.

Concept 13: batching

بعض الأعمال أرخص بالجملة: embeddings، تقارير يومية، أو syncs. اجمع عندما لا يضر latency ولا يزيد خطر الفشل.

Concept 14: replay والإلغاء الجماعي

replay يساعدك على إصلاح bug ثم إعادة أحداث تأثرت به. bulk cancellation يوقف موجة خاطئة. كلاهما يحتاج سجلاً واضحاً لما حدث ولماذا.

Concept 15: بوابات HITL بـ step.wait_for_event

الموافقة البشرية ليست نافذة منبثقة. في الإنتاج هي event ينتظره العامل: طلب موافقة، رابط قرار، توقيع، ثم متابعة أو إلغاء.

الجزء 4: المثال العملي، عامل دعم عملاء إنتاجي

الموجز

نأخذ عامل الدعم من الدورة السابقة ونغلفه بـ Inngest. بدلاً من أن يرد عندما تكتب أنت، سيستيقظ عند وصول بريد، وسيشغل فحصاً يومياً لصحة العملاء، وسيصعد الحالات الحساسة إلى إنسان.

Decision 1: تحديث ملف القواعد بطبقة Inngest

أضف إلى AGENTS.md أن العمل الإنتاجي يمر عبر أحداث وخطوات durable، وأن أي استدعاء خارجي مهم يحتاج idempotency أو سجل audit.

Decision 2: تثبيت مهارات Inngest وربط dev-server MCP

استخدم مهارة أو مرجعاً يحفظ أوامر التشغيل، أسماء الملفات، وكيفية قراءة dashboard المحلي. لا تجعل الوكيل يخمن API من ذاكرته.

Decision 3: تغليف عامل الدعم داخل دالة Inngest

import inngest

@inngest.create_function(
fn_id="support-handle-email",
trigger=inngest.TriggerEvent(event="email.received"),
)
async def handle_email(ctx, step):
ticket = ctx.event.data
summary = await step.run("summarize", lambda: summarize_ticket(ticket))
decision = await step.run("decide", lambda: route_ticket(summary))
return {"decision": decision}

Decision 4: إضافة محفز email.received

حوّل webhook البريد إلى event داخلي. لا تمرر payload ضخماً بلا تنظيف. خزّن raw payload عند الحاجة في audit، ومرر المعرفات والحقول الضرورية فقط.

Decision 5: فحص يومي لصحة العملاء مع fan-out

Cron يومي يجلب العملاء النشطين، ثم يرسل event لكل عميل يحتاج فحصاً. fan-out يمنع دالة واحدة من حمل كل العمل.

Decision 6: حدود concurrency ومعدل الاستدعاء

ضع حدوداً تناسب OpenAI rate limit وPostgres pool. إذا زادت الأخطاء عند الحمل، لا ترفع القوة فقط؛ افهم أي مورد يختنق.

أثر الكلفة

التحكم في concurrency ليس فقط للثبات. إنه يحمي فاتورة النموذج وقاعدة البيانات من موجة غير مقصودة.

Decision 7: بوابة تصعيد HITL

إذا احتاج refund كبير أو تغيير عقد، يكتب العامل طلب موافقة ثم ينتظر event. لا يعلق process؛ تعلق المنصة خطوة durable.

Decision 8: تحقق end-to-end بسيناريو replay

أرسل event تجريبي، شاهد dashboard، افشل خطوة عمداً، أعد التشغيل، وتحقق أن الخطوات الناجحة لم تتكرر بطريقة خطرة.

ما الذي حدث

لم تغيّر ذكاء العامل. غيّرت غلافه التشغيلي: من دالة تستدعيها يدوياً إلى عامل يستيقظ من العالم، ينتظر بأمان، يستأنف بعد الفشل، ويترك أثراً قابلاً للتدقيق.

الجزء 5: أين تتوقف هذه الدورة

شكل الكلفة لعامل الإنتاج

الكلفة تأتي من عدد الأحداث، وعدد خطوات النموذج، ومدة الانتظار، والتخزين، وعدد replay. المتانة لا تلغي الكلفة؛ تجعلها مرئية وقابلة للتحكم.

دليل الاستبدال

Inngest هو المنصة في المختبر. Temporal أو Restate أو Dapr Agents يمكن أن تحمل الأنماط نفسها: event، step، retry، wait، replay، observability. الغلاف التشغيلي invariant؛ المنتج متغير.

ما لا تغطيه الدورة بعد

لا تغطي إدارة قوة العمل، التوظيف الديناميكي، ولا تفويض المالك. هذه تأتي في الدورات التالية. هنا نتعلم كيف ينجو عامل واحد من الإنتاج.

كيف تتحسن فعلاً

خذ workflow موجوداً يعمل يدوياً. ارسم أحداثه وخطواته وانتظاراته. اسأل: أين قد يتعطل؟ ما الذي يجب ألا يتكرر؟ أين نحتاج إنساناً؟ ثم غلفه بمحرك durable قبل إضافة ميزات جديدة.

مرجع سريع

المفاهيم الخمسة عشر

#المفهومالسؤال العملي
1events vs requestsهل ينتظر المتصل أم يطلق حدثاً؟
2cronهل الوقت هو المحفز؟
3webhookهل العالم الخارجي يستدعيك؟
4idempotencyماذا لو وصل الحدث مرتين؟
5fan-outهل يحتاج الحدث إلى عمال متعددين؟
6step.runأين حدود الخطوات؟
7memoizationماذا لا يجب أن يعاد؟
8sleep/waitهل ننتظر وقتاً أو حدثاً؟
9retriesمتى نتوقف عن المحاولة؟
10AI callsهل استدعاء النموذج داخل خطوة durable؟
11concurrencyما الحد الآمن؟
12fairnessهل عميل واحد يؤذي الآخرين؟
13batchingما الذي يجب جمعه؟
14replay/cancelكيف نتعافى من bug؟
15HITLأين ينتظر الإنسان؟

شجرة اختيار المحفز

حدث خارجي؟ -> webhook -> event داخلي.
وقت محدد؟ -> cron.
نتيجة عامل آخر؟ -> event.
قرار إنسان؟ -> wait_for_event.

تشخيص سريع

خطوة تعاد وتسبب أثراً خارجياً -> أضف idempotency.
الحمل يخنق قاعدة البيانات -> concurrency limit.
المهمة تنتظر داخل process -> استخدم step.sleep أو wait_for_event.
لا تعرف ماذا حدث -> افحص trace وactivity log.

ملحق: تذكير بالمتطلبات

A.1 ما تفترضه الدورة السابقة

لديك عامل مبني بـ OpenAI Agents SDK، ومهارات، وقاعدة Neon، وخادم MCP، وسجل audit. هذه الدورة لا تعيد بناء ذلك؛ تغلفه بتشغيل إنتاجي.

A.2 أساسيات Inngest المستخدمة هنا

تحتاج معرفة event، function، trigger، step، retry، dev server، وdashboard. الباقي يمكن تعلمه عند الحاجة.

A.3 ما لا يستبدله هذا الملحق

لا يغني عن وثائق Inngest ولا عن اختبار إنتاجي حقيقي. استخدمه كخريطة ذهنية، ثم تحقق من API الحالي قبل الشحن.