أعد محاولة الوظائف غير المتزامنة

يصف هذا المستند كيف يمكنك طلب وظائف الخلفية غير المتزامنة (بخلاف HTTPS) لإعادة المحاولة عند الفشل.

دلالات إعادة المحاولة

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

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

لماذا تفشل الوظائف التي تحركها الأحداث في الإكمال

في حالات نادرة ، قد يتم إنهاء إحدى الوظائف قبل الأوان بسبب خطأ داخلي ، وبشكل افتراضي قد تتم إعادة محاولة الوظيفة تلقائيًا أو لا.

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

  • تحتوي الوظيفة على خطأ ويطرح وقت التشغيل استثناءً.
  • لا يمكن أن تصل الوظيفة إلى نقطة نهاية الخدمة ، أو تنتهي مهلتها أثناء محاولة الوصول إلى نقطة النهاية.
  • تطرح الوظيفة استثناءً عمدًا (على سبيل المثال ، عندما تفشل المعلمة في التحقق من الصحة).
  • عندما تُعيد الدوال المكتوبة في Node.js وعدًا مرفوضًا أو تمرر قيمة غير null إلى رد نداء.

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

تمكين وتعطيل عمليات إعادة المحاولة

استخدام وحدة تحكم GCP

يمكنك تمكين أو تعطيل عمليات إعادة المحاولة في وحدة تحكم GCP على النحو التالي:

  1. انتقل إلى صفحة نظرة عامة على وظائف السحابة في وحدة تحكم Cloud Platform.

  2. انقر فوق إنشاء وظيفة . بدلاً من ذلك ، انقر فوق دالة موجودة للانتقال إلى صفحة التفاصيل الخاصة بها وانقر فوق تحرير .

  3. املأ الحقول المطلوبة لوظيفتك.

  4. تأكد من تعيين حقل المشغل على نوع المشغل المستند إلى الحدث ، مثل Cloud Pub / Sub أو Cloud Storage.

  5. قم بتوسيع الإعدادات المتقدمة بالنقر فوق المزيد .

  6. حدد أو ألغِ تحديد المربع المسمى إعادة المحاولة عند الفشل .

في كود الوظيفة

باستخدام وظائف السحابة لـ Firebase ، يمكنك تمكين عمليات إعادة المحاولة في التعليمات البرمجية لوظيفة ما. للقيام بذلك لوظيفة خلفية مثل functions.foo.onBar(myHandler); ، استخدم runWith وقم بتكوين سياسة فشل:

functions.runWith({failurePolicy: true}).foo.onBar(myHandler);

يؤدي الضبط على " true " كما هو موضح إلى تكوين وظيفة لإعادة المحاولة عند الفشل.

أفضل الممارسات

يصف هذا القسم أفضل الممارسات لاستخدام عمليات إعادة المحاولة.

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

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

قم بتعيين شرط النهاية لتجنب حلقات إعادة المحاولة اللانهائية

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

نهج بسيط ولكنه فعال هو تجاهل الأحداث ذات الطوابع الزمنية الأقدم من وقت معين. يساعد هذا في تجنب عمليات الإعدام المفرطة عندما تكون حالات الفشل إما مستمرة أو أطول عمراً مما هو متوقع.

على سبيل المثال ، يتجاهل مقتطف الشفرة هذا جميع الأحداث الأقدم من 10 ثوانٍ:

const eventAgeMs = Date.now() - Date.parse(event.timestamp);
const eventMaxAgeMs = 10000;
if (eventAgeMs > eventMaxAgeMs) {
  console.log(`Dropping event ${event} with age[ms]: ${eventAgeMs}`);
  callback();
  return;
}

استخدم catch بالوعود"

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

فيما يلي مثال لما يجب عليك فعله:

return doFooAsync().catch((err) => {
    if (isFatal(err)) {
        console.error(`Fatal error ${err}`);
    }
    return Promise.reject(err);
});

اجعل الوظائف القابلة لإعادة المحاولة التي تستند إلى الأحداث عاطلة عن العمل

يجب أن تكون الوظائف التي تستند إلى الأحداث والتي يمكن إعادة تجربتها غير فعالة. فيما يلي بعض الإرشادات العامة لجعل مثل هذه الوظيفة غير فعالة:

  • تتيح لك العديد من واجهات برمجة التطبيقات الخارجية (مثل Stripe) توفير مفتاح idempotency كمعامل. إذا كنت تستخدم مثل API ، فيجب عليك استخدام معرف الحدث كمفتاح idempotency.
  • تعمل Idempotency بشكل جيد مع التسليم مرة واحدة على الأقل ، لأنها تجعل إعادة المحاولة آمنة. لذا فإن أفضل ممارسة عامة لكتابة تعليمات برمجية موثوقة هي الجمع بين idempotency وإعادة المحاولات.
  • تأكد من أن شفرتك غير فعالة داخليًا. فمثلا:
    • تأكد من أن الطفرات يمكن أن تحدث أكثر من مرة دون تغيير النتيجة.
    • حالة قاعدة بيانات الاستعلام في معاملة قبل تغيير الحالة.
    • تأكد من أن جميع الآثار الجانبية هي نفسها معطلة.
  • فرض فحص معاملات خارج الوظيفة ، بغض النظر عن الكود. على سبيل المثال ، استمر في تسجيل الحالة في مكان ما أن معرف حدث معين قد تمت معالجته بالفعل.
  • التعامل مع المكالمات وظيفة مكررة خارج النطاق. على سبيل المثال ، لديك عملية تنظيف منفصلة يتم تنظيفها بعد استدعاءات الوظائف المكررة.