AWS وسّعت Durable Functions: إمتى تستبدل الـ queue المخصص؟
لو عندك workflow بتقع في نصها وتحتاج تكمل من آخر خطوة، توسع AWS Lambda Durable Functions يوم 22 أبريل 2026 يفتح اختيار عملي جديد: تكتب orchestration أقل، لكن تقبل ارتباط أقوى ببيئة Lambda.
مستوى القارئ: متوسط
المشكلة باختصار
الطريقة الشائعة في فرق كتير إنك تبني state table في DynamoDB، وتحط retry worker، وتضيف queue بين كل خطوة وخطوة. الطريقة دي بتشتغل، لكنها بتفشل تدريجيًا لما الـ workflow يبقى فيه انتظار طويل أو callback من خدمة خارجية.
مثال واضح: عندك onboarding لشركة جديدة. الخطوات هي إنشاء tenant، شحن بطاقة، انتظار موافقة مسؤول، إرسال بريد، ثم تفعيل الحساب. لو الخطوة الثالثة أخدت 6 ساعات، Lambda العادية لا ينفع تفضل نايمة. ولو كتبت sleep داخل الكود فأنت بتدفع compute بلا قيمة.
AWS أعلنت في 22 أبريل 2026 إن Lambda Durable Functions أصبحت متاحة في 16 منطقة إضافية، منها London وParis وZurich وTel Aviv وSão Paulo وUS West N. California. الخبر مهم لأنه يقرب نفس النمط من المستخدم والبيانات، بدل ما تبقى مربوط بمنطقة واحدة بعيدة.
الفكرة ببساطة قبل التعريف الرسمي
ركز في المثال ده: بدل ما تكتب عامل منفصل يتابع هل الدفع تم أم لا، بتكتب دالة واحدة فيها خطوات. خطوة تدفع. خطوة تنتظر webhook. خطوة ترسل الإيميل. لو التنفيذ وقع بعد الدفع، النظام لا يعيد الدفع من جديد. هو يعيد تشغيل الدالة ويستخدم نتيجة الخطوة المكتملة من checkpoint.
التعريف الدقيق: Durable Functions تضيف primitives داخل handler مثل steps وwaits. الـ step يحفظ تقدم العملية، والـ wait يوقف التنفيذ ثم يستأنفه لاحقًا. حسب وثائق AWS، الـ wait لا يستهلك زمن تنفيذ Lambda أثناء التوقف في on-demand functions، والحد الأعلى للانتظار يمكن أن يصل إلى سنة في نمط الانتظار.
اللي بيحصل فعلاً إن الدالة قد تُستدعى أكثر من مرة. عند الاستئناف، Lambda تعيد تشغيل الكود من البداية، لكنها تتخطى الخطوات المكتملة وتعيد نتائجها من سجل الـ checkpoint. لهذا السبب لازم يكون الكود deterministic. يعني لا تعتمد على Date.now() أو random داخل قرار مهم إلا لو حفظت النتيجة كجزء من step.
مثال تنفيذي: order workflow صغير
الافتراض إن عندك خدمة طلبات أقل من 20 ألف طلب يوميًا، وكل طلب يحتاج دفع ثم انتظار webhook ثم إرسال بريد. هذا مثال Node.js توضيحي قريب من نمط durable handler. أسماء الحزم قد تختلف حسب SDK النهائي في مشروعك، لكن الفكرة التنفيذية هي ترتيب الخطوات وفصل التأثيرات الجانبية داخل steps مسماة.
export const handler = async (event, context) => {
const durable = context.durable;
const order = await durable.step("load-order", async () => {
return await getOrder(event.orderId);
});
const charge = await durable.step("charge-card", async () => {
return await stripe.paymentIntents.create({
amount: order.amountCents,
currency: "usd",
customer: order.customerId
});
});
await durable.waitForCallback("payment-webhook", {
timeoutSeconds: 60 * 60 * 24
});
await durable.step("send-confirmation", async () => {
return await sendEmail(order.email, charge.id);
});
return { ok: true, orderId: order.id };
};