توضِّح هذه المقالة كيفية طلب إعادة محاولة تنفيذ الدوال غير المتزامنة (غير المستندة إلى بروتوكول HTTPS) في الخلفية عند حدوث خطأ.
أسباب تعذُّر إكمال الدوال المستندة إلى الأحداث
في حالات نادرة، قد تتوقف دالة عن العمل قبل الأوان بسبب خطأ داخلي، وقد تتم إعادة محاولة تنفيذها تلقائيًا أو لا تتم، وذلك حسب الإعدادات التلقائية.
في حالات أكثر شيوعًا، قد يتعذّر إكمال دالة مستندة إلى الأحداث بنجاح بسبب أخطاء يتم طرحها في رمز الدالة نفسه. وتشمل الأسباب المحتمَلة ما يلي:
- تحتوي الدالة على خطأ، ويطرح وقت التشغيل استثناءً.
- لا يمكن للدالة الوصول إلى نقطة نهاية خدمة، أو تنتهي مهلتها أثناء محاولة الوصول إليها.
- تطرح الدالة استثناءً عن قصد (على سبيل المثال، عندما يتعذّر التحقق من صحة مَعلمة).
- تعرض دالة Node.js وعدًا مرفوضًا، أو تمرِّر قيمة غير
nullإلى دالة معاودة الاتصال.
في أيّ من الحالات أعلاه، ستتوقف الدالة عن التنفيذ وتعرض خطأً. تتضمّن مشغّلات الأحداث التي تنشئ الرسائل سياسات إعادة محاولة يمكنك تخصيصها لتلبية احتياجات دالتك.
معاني إعادة المحاولة
Cloud Functions توفّر عملية تنفيذ واحدة على الأقل لدالة مستندة إلى الأحداث لكل حدث يتم إرساله من مصدر حدث. إذا انتهت عملية استدعاء دالة بسبب خطأ، لا يتم استدعاء الدالة مرة أخرى ويتم تجاهل الحدث. عند تفعيل عمليات إعادة المحاولة في دالة مستندة إلى الأحداث، Cloud Functions تعيد محاولة استدعاء دالة تعذّر تنفيذها إلى أن تكتمل بنجاح أو تنتهي مهلة نافذة إعادة المحاولة.
عندما لا تكون عمليات إعادة المحاولة مفعّلة لدالة (وهو الإعداد التلقائي)، تشير الدالة دائمًا إلى أنّها تم تنفيذها بنجاح، وقد تظهر رموز استجابة 200 OK في سجلّاتها. يحدث ذلك حتى إذا واجهت الدالة خطأً. لتوضيح متى تواجه دالتك خطأً، احرص على
الإبلاغ عن الأخطاء
بشكلٍ مناسب.
ضبط عمليات إعادة المحاولة من رمز الدالة
باستخدام Cloud Functions for Firebase، يمكنك تفعيل عمليات إعادة المحاولة في رمز الدالة. لإجراء ذلك في حدث في الخلفية، مثل إنشاء مستند Firestore جديد، اضبط خيار failurePolicy (الجيل الأول) أو retry (الجيل الثاني) على true:
الجيل الأول
exports.docCreated = functions
.runWith({
// retry on failure
failurePolicy: true,
})
.firestore.document("my-collection/{docId}")
.onCreate((change, context) => {
/* ... */
});
الجيل الثاني
const { onDocumentCreated } = require("firebase-functions/firestore");
exports.docCreated = onDocumentCreated(
{
// retry on failure
retry: true,
},
"my-collection/{docId}",
(event) => {
/* ... */
},
);
يؤدي ضبط true كما هو موضّح إلى إعداد دالة لإعادة المحاولة عند حدوث خطأ.
نافذة إعادة المحاولة
بالنسبة إلى دوال الجيل الثاني، تنتهي مهلة نافذة إعادة المحاولة هذه بعد 24 ساعة. بالنسبة إلى دوال الجيل الأول، تنتهي مهلتها بعد 7 أيام. Cloud Functions تعيد محاولة تنفيذ الدوال المستندة إلى الأحداث التي تم إنشاؤها حديثًا باستخدام استراتيجية التراجع الأسي، مع زيادة فترة التراجع بين 10 ثوانٍ و600 ثانية. يتم تطبيق هذه السياسة على الدوال الجديدة في أول مرة تنشرها. لا يتم تطبيقها بأثر رجعي على الدوال الحالية التي تم نشرها لأول مرة قبل أن تصبح التغييرات الموضّحة فيملاحظة الإصدار هذهسارية، حتى إذا أعدت نشر الدوال.أفضل الممارسات
يوضِّح هذا القسم أفضل الممارسات لاستخدام عمليات إعادة المحاولة.
استخدام إعادة المحاولة للتعامل مع الأخطاء العابرة
بما أنّه تتم إعادة محاولة تنفيذ دالتك بشكلٍ مستمر إلى أن يتم تنفيذها بنجاح، يجب إزالة الأخطاء الدائمة، مثل الأخطاء البرمجية، من الرمز من خلال الاختبار قبل تفعيل عمليات إعادة المحاولة. يُفضَّل استخدام عمليات إعادة المحاولة للتعامل مع حالات الفشل المتقطّعة أو العابرة التي من المرجّح أن يتم حلّها عند إعادة المحاولة، مثل نقطة نهاية خدمة غير موثوق بها أو انتهاء المهلة.
ضبط شرط إنهاء لتجنُّب حلقات إعادة المحاولة اللانهائية
من أفضل الممارسات حماية دالتك من التكرار المستمر عند استخدام عمليات إعادة المحاولة. يمكنك إجراء ذلك من خلال تضمين شرط إنهاء محدّد جيدًا قبل أن تبدأ الدالة في المعالجة. يُرجى العِلم أنّ هذه التقنية لا تعمل إلا إذا بدأت دالتك بنجاح وتمكّنت من تقييم شرط الإنهاء.
هناك نهج بسيط وفعّال يتمثل في تجاهل الأحداث التي تحمل طوابع زمنية أقدم من وقت معيّن. يساعد ذلك في تجنُّب عمليات التنفيذ المفرطة عندما تكون حالات الفشل مستمرة أو أطول من المتوقّع.
على سبيل المثال، يتجاهل مقتطف الرمز هذا جميع الأحداث التي مرّ عليها أكثر من 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) تقديم مفتاح تطابق كمعلَمة. إذا كنت تستخدم إحدى هذه الواجهات، عليك استخدام رقم تعريف الحدث كمفتاح تطابق.
- يعمل التطابق بشكلٍ جيد مع عملية التسليم مرة واحدة على الأقل، لأنّه يجعل إعادة المحاولة آمنة. لذا، من أفضل الممارسات العامة لكتابة رمز موثوق به الجمع بين التطابق وعمليات إعادة المحاولة.
- تأكَّد من أنّ الرمز متطابق داخليًا. على سبيل المثال:
- تأكَّد من إمكانية إجراء عمليات التغيير أكثر من مرة بدون تغيير النتيجة.
- استعلم عن حالة قاعدة البيانات في معاملة قبل تغيير الحالة.
- تأكَّد من أنّ جميع الآثار الجانبية متطابقة بحد ذاتها.
- فرض عملية تحقّق من المعاملة خارج الدالة، بشكلٍ مستقل عن الرمز. على سبيل المثال، يمكنك الاحتفاظ بالحالة في مكان ما لتسجيل أنّه تمّت معالجة رقم تعريف حدث معيّن من قبل.
- التعامل مع عمليات استدعاء الدوال المكرّرة خارج النطاق. على سبيل المثال، يمكنك إجراء عملية تنظيف منفصلة تنظّف بعد عمليات استدعاء الدوال المكرّرة.
ضبط سياسة إعادة المحاولة
بناءً على احتياجات دالتك، قد تحتاج إلى ضبط سياسة إعادة المحاولة مباشرةً. سيسمح لك ذلك بإعداد أي مجموعة من الخيارات التالية:
- تقصير نافذة إعادة المحاولة من 7 أيام إلى 10 دقائق على الأقل.
- تغيير الحد الأدنى والأقصى لوقت التراجع لاستراتيجية إعادة المحاولة باستخدام التراجع الأسي.
- تغيير استراتيجية إعادة المحاولة لإعادة المحاولة فورًا.
- ضبط موضوع الرسائل غير القابلة للتسليم .
- ضبط الحد الأقصى والأدنى لعدد محاولات التسليم.
لضبط سياسة إعادة المحاولة:
- اكتب دالة HTTP.
- استخدِم واجهة برمجة تطبيقات Pub/Sub لإنشاء اشتراك في Pub/Sub، مع تحديد عنوان URL لـ الدالة كهدف.
لمزيد من المعلومات حول ضبط Pub/Sub مباشرةً، اطّلِع على مستندات Pub/Sub حول معالجة حالات الفشل.