0Pricing
Cloud & IT Cert Prep · درس

Durable Functions لسير العمل ذي الحالة

نسّق عمليات سير العمل طويلة الأمد باستخدام أنماط المنسّق في Durable Functions (التوزيع والتجميع، والتسلسل، والمراقبة)، وتعرّف على كيفية حفظ نقاط التحقق للحالة.

Durable Functions لسير العمل ذي الحالة درس مجاني في Cloud & IT Cert Prep على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Cloud & IT Cert Prep، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Cloud & IT Cert Prep 4 دروس في المجموع.

لماذا Durable Functions؟

تكون Azure Functions العادية عديمة الحالة — إذ يعمل كل استدعاء بشكل مستقل من دون الاحتفاظ بذاكرة عن الاستدعاءات السابقة. وتوسّع Durable Functions إمكانات Azure Functions بإتاحة كتابة مهام سير عمل طويلة الأمد وذات حالة باستخدام تعليمات async/await البرمجية العادية. ويُنشئ Durable Task Framework نقاط حفظ للحالة تلقائيًا في Azure Storage بعد كل خطوة، لذلك يمكن لمهام سير العمل تحمّل إعادة تشغيل الخوادم أو انتهاء المهلات أو الصيانة المخطط لها، ثم استئناف العمل من الموضع الذي توقفت عنده تمامًا.

أنواع الدوال الثلاثة

تقدم Durable Functions ثلاثة أنواع من الدوال. تعمل دالة المنسّق على تنسيق مهمة سير العمل بأكملها — إذ تستدعي دوال الأنشطة وتنتظر النتائج باستخدام yield أو await من دون حظر مؤشر ترابط فعليًا. وتنفّذ دالة النشاط وحدة عمل واحدة (مثل استدعاء API أو الكتابة إلى قاعدة بيانات)، وهي المكان الوحيد الذي ينبغي أن تحدث فيه الآثار الجانبية. أما دالة الكيان فتحافظ على أجزاء صغيرة من الحالة الدائمة (مثل العدادات والعلامات) بين الاستدعاءات.

// Client function (HTTP trigger) — starts the orchestration
module.exports = async function (context, req) {
  const client = df.getClient(context);
  const orderId = req.body.orderId;
  const instanceId = await client.startNew('OrderOrchestrator', undefined, { orderId });
  return client.createCheckStatusResponse(context.bindingData.req, instanceId);
};

نمط التسلسل

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

// Orchestrator: chaining pattern
const df = require('durable-functions');
module.exports = df.orchestrator(function* (context) {
  const orderId = context.df.getInput().orderId;

  const validated = yield context.df.callActivity('ValidateOrder', orderId);
  const charged   = yield context.df.callActivity('ChargePayment', validated);
  const shipped   = yield context.df.callActivity('ShipOrder', charged);

  return { status: 'shipped', trackingId: shipped.trackingId };
});

نمط التوزيع والتجميع

يشغّل نمط التوزيع/التجميع عدة دوال أنشطة بالتوازي، وينتظر اكتمالها جميعًا قبل المتابعة. ويبدأ المنسّق جميع المهام في الوقت نفسه باستخدام callActivity من دون انتظارها، ثم يجمع كائنات المهام في صفيف، وينتظر على Task.all(). ويكون هذا أسرع بكثير من المعالجة التسلسلية عند التعامل مع عناصر عمل مستقلة، مثل معالجة ملفات متعددة أو استدعاء عدة واجهات API أو تنفيذ عمليات دفعية.

// Orchestrator: fan-out / fan-in
module.exports = df.orchestrator(function* (context) {
  const items = context.df.getInput().items;

  // Fan-out: start all tasks in parallel
  const tasks = items.map(item => context.df.callActivity('ProcessItem', item));

  // Fan-in: wait for all tasks to complete
  const results = yield context.df.Task.all(tasks);

  return results;
});

نمط المراقبة

يفحص نمط المراقبة نظامًا خارجيًا على فترات زمنية حتى يتحقق شرط معين — وهو يشبه حلقة polling، لكنه دائم الاستمرارية بالكامل. يستدعي المنسّق نشاطًا للتحقق من الحالة، وينتظر فترة زمنية قابلة للتهيئة باستخدام createTimer، ثم يكرر العملية. وبما أن الحالة تُحفظ في التخزين بين كل عملية فحص، فلا يستهلك المنسّق موارد حوسبة أثناء الانتظار، مما يجعله أكثر كفاءة بكثير من أسلوب مؤقت قائم على السكون.

// Orchestrator: monitor pattern (poll until job completes)
module.exports = df.orchestrator(function* (context) {
  const jobId = context.df.getInput().jobId;
  const expiry = new Date(context.df.currentUtcDateTime);
  expiry.setHours(expiry.getHours() + 24); // 24-hour timeout

  while (context.df.currentUtcDateTime < expiry) {
    const status = yield context.df.callActivity('GetJobStatus', jobId);
    if (status === 'completed') return { jobId, status };
    if (status === 'failed') throw new Error('Job failed');
    // Wait 30 seconds before next poll
    const nextCheck = new Date(context.df.currentUtcDateTime);
    nextCheck.setSeconds(nextCheck.getSeconds() + 30);
    yield context.df.createTimer(nextCheck);
  }
  throw new Error('Workflow timed out');
});

نمط التفاعل البشري

يوقف نمط التفاعل البشري عملية التنسيق مؤقتًا وينتظر حدثًا خارجيًا — مثل موافقة مدير. وينتظر المنسّق باستخدام waitForExternalEvent، الذي يمكنه الانتظار أيامًا أو أسابيع من دون استهلاك موارد الحوسبة. ويستدعي نظام خارجي (مثل رابط موافقة عبر البريد الإلكتروني أو تطبيق جوال أو webhook) واجهة HTTP البرمجية لـ Durable Functions لرفع الحدث، مما يتيح استئناف عملية التنسيق. ويمكن دمج ذلك مع مؤقت لتطبيق مهلة تلقائية وتصعيد الإجراء إذا لم تصل استجابة.

// Orchestrator: wait for human approval with timeout
module.exports = df.orchestrator(function* (context) {
  const request = context.df.getInput();

  yield context.df.callActivity('SendApprovalEmail', request);

  const timeout = df.Task.createTimer(context, new Date(Date.now() + 48 * 3600 * 1000));
  const approval = context.df.waitForExternalEvent('ApprovalResponse');

  const winner = yield context.df.Task.any([approval, timeout]);

  if (winner === approval) {
    const approved = winner.result;
    return approved ? 'Approved' : 'Rejected';
  } else {
    return 'Timed out — escalated';
  }
});

قيود المنسّق

تفرض دوال المنسّق قيودًا مهمة لأنها قد تُعاد من سجل المحفوظات عدة مرات لإعادة بناء الحالة. ويجب أن تكون حتمية — لذلك لا تستخدموا Date.now() أو Math.random()، ولا تُجروا استدعاءات I/O مباشرة. وبدلًا من ذلك، استخدموا context.df.currentUtcDateTime للطوابع الزمنية، واستدعوا دوال الأنشطة لتنفيذ جميع عمليات I/O. وسيؤدي تسجيل الأحداث داخل نص المنسّق إلى إنشاء إدخالات سجل مكررة أثناء إعادة التشغيل؛ لذا استخدموا دوال الأنشطة للتسجيل بدلًا من ذلك.

// WRONG — non-deterministic, will cause replay bugs
module.exports = df.orchestrator(function* (context) {
  const now = new Date();          // Don't use Date()
  const rand = Math.random();       // Don't use Math.random()
  const data = await fetch('/api'); // Don't make HTTP calls directly
});

// CORRECT
module.exports = df.orchestrator(function* (context) {
  const now = context.df.currentUtcDateTime; // OK
  const data = yield context.df.callActivity('FetchData', null); // OK
});

إدارة المثيلات: الحالة والإنهاء

لكل عملية تنسيق معرّف مثيل فريد يمكنكم استخدامه للاستعلام عن حالتها أو إرسال أحداث إليها أو إنهائها. وتوفر واجهة إدارة HTTP البرمجية لـ Durable Functions نقاط نهاية للتحقق من الحالة (GET /instances/{id}) وإرسال الأحداث (POST /instances/{id}/raiseEvent/{name}) والإنهاء (POST /instances/{id}/terminate). استخدموا رابط عميل Durable في دوالكم للوصول إلى هذه العمليات برمجيًا.

// Client function: check orchestration status
module.exports = async function (context, req) {
  const client = df.getClient(context);
  const instanceId = req.params.instanceId;

  const status = await client.getStatus(instanceId, true, true, true);
  return {
    status: 200,
    body: {
      instanceId,
      runtimeStatus: status.runtimeStatus,
      customStatus: status.customStatus,
      output: status.output
    }
  };
};

واجهة التخزين الخلفية والأداء

تخزّن Durable Functions سجل عمليات التنسيق وحالة المثيلات وقوائم انتظار الرسائل بين الدوال في حساب Azure Storage (أو في واجهات Azure SQL/Netherite الخلفية لتحقيق معدل نقل أعلى). وتكتب كل نقطة حفظ إلى Azure Table Storage وAzure Queue Storage. وفي السيناريوهات ذات معدل النقل العالي (آلاف عمليات التنسيق المتزامنة)، تستخدم واجهة تخزين Netherite الخلفية Azure Event Hubs لتحقيق أداء أفضل بكثير. راقبوا عمق قائمة انتظار عمليات التنسيق لاكتشاف الاختناقات.

// host.json: configure the Durable Task storage provider
{
  'version': '2.0',
  'extensions': {
    'durableTask': {
      'hubName': 'MyTaskHub',
      'storageProvider': {
        'type': 'azure',
        'connectionStringName': 'AzureWebJobsStorage',
        'controlQueueBatchSize': 32,
        'maxQueuePollingInterval': '00:00:02'
      }
    }
  }
}

معالجة الأخطاء وإعادة المحاولات

يمكن لدوال الأنشطة طرح استثناءات تنتقل إلى المنسّق على هيئة TaskFailedException. استخدموا كتل try-catch في المنسّق لمعالجة حالات الفشل بسلاسة. وبالنسبة إلى الأخطاء المؤقتة، كوّنوا إعادات المحاولة التلقائية مع التراجع التدريجي باستخدام callActivityWithRetry، مع تحديد الحد الأقصى للمحاولات وفاصل إعادة المحاولة الأولي ومعامل التراجع التدريجي. وهذا هو النمط الموصى به للأنشطة التي تستدعي واجهات API أو قواعد بيانات خارجية.

// Orchestrator: retry an activity with exponential backoff
module.exports = df.orchestrator(function* (context) {
  const retryOptions = new df.RetryOptions(
    5000,  // firstRetryIntervalInMilliseconds
    3      // maxNumberOfAttempts
  );
  retryOptions.backoffCoefficient = 2; // 5s, 10s, 20s

  try {
    const result = yield context.df.callActivityWithRetry(
      'CallExternalAPI',
      retryOptions,
      context.df.getInput()
    );
    return result;
  } catch (e) {
    yield context.df.callActivity('SendFailureAlert', e.message);
    throw e;
  }
});

الكيانات الدائمة

تطبّق Durable Entities (دوال الكيانات) أجزاء صغيرة من الحالة الدائمة يمكن الوصول إليها باستخدام الهوية — على نحو يشبه virtual actors. للكيان معرّف وحالة تستمر بين الاستدعاءات. ويمكنكم استدعاء عمليات على كيان من منسّق أو عميل، ويعالج الكيان هذه العمليات واحدة تلو الأخرى (بشكل تسلسلي). وتشمل الاستخدامات الشائعة العدادات وآلات حالات الموافقة ومحددات معدل الطلبات وسلال التسوق — أي سيناريو يحتاج إلى حالة دائمة قابلة للتحديث من دون قاعدة بيانات.

// Counter entity function
const df = require('durable-functions');
module.exports = df.entity(function (context) {
  let count = context.df.getState(() => 0);
  const operation = context.df.operationName;

  if (operation === 'add') count += context.df.getInput();
  if (operation === 'reset') count = 0;
  if (operation === 'get') context.df.return(count);

  context.df.setState(count);
});

// From orchestrator, increment counter entity
// const entityId = new df.EntityId('Counter', 'myCounter');
// yield context.df.callEntity(entityId, 'add', 1);

تحقّق سريع

اختبر مدى استيعابكم لمفاهيم Microsoft Azure Fundamentals (AZ-900) الواردة في هذا الدرس.

مراجعة الدرس

تعلّمتم في هذا الدرس أن Durable Functions تتيح مهام سير عمل طويلة الأمد وذات حالة من خلال حفظ حالة المنسّق في نقاط حفظ داخل Azure Storage، وأن الأنماط الأساسية تشمل التسلسل والتوزيع/التجميع والمراقبة والتفاعل البشري، وأن المنسّقات يجب أن تكون حتمية — إذ يجب تمرير جميع عمليات I/O والاستدعاءات غير الحتمية عبر دوال الأنشطة. في الدرس التالي، سنستكشف Azure Logic Apps.

الأسئلة الشائعة

هل درس «Durable Functions لسير العمل ذي الحالة» مجاني؟

نعم — نص درس «Durable Functions لسير العمل ذي الحالة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Cloud & IT Cert Prep، انتقل إلى CoddyKit PRO. تتضمن دورة Cloud & IT Cert Prep 4 دروس في المجموع.

ماذا ستتعلم في «Durable Functions لسير العمل ذي الحالة»؟

نسّق عمليات سير العمل طويلة الأمد باستخدام أنماط المنسّق في Durable Functions (التوزيع والتجميع، والتسلسل، والمراقبة)، وتعرّف على كيفية حفظ نقاط التحقق للحالة. تتمرن على Cloud & IT Cert Prep مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Cloud & IT Cert Prep؟

لا تُشترط خبرة سابقة. Cloud & IT Cert Prep على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «Durable Functions لسير العمل ذي الحالة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Cloud & IT Cert Prep هذا؟

نعم. كل درس في Cloud & IT Cert Prep يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. المشغّلات والارتباطات في Azure Functions
  2. Durable Functions لسير العمل ذي الحالة
  3. Azure Logic Apps
  4. Event Grid والبنية المستندة إلى الأحداث
← العودة إلى Cloud & IT Cert Prep