تعد المحاولات واحدة من أسهل ميزات المرونة التي يمكن أن تُخطئ، لأنها تبدو غير ضارة على نطاق صغير.
إعادة محاولة خدمة واحدة لطلب فاشل ليست مشكلة. لكن عشرة آلاف حالة تحاول إعادة المحاولة في نفس الجدول الزمني غالباً ما تكون كذلك.
هنا يصبح منطق إعادة المحاولة من آلية استرداد إلى معزز للحمل.
النمط الساذج
هذا شائع وخطير:
for (let attempt = 0; attempt < 3; attempt += 1) {
try {
return await callPaymentApi();
} catch (error) {
await sleep(1000);
}
}
تفشل جميع المتصلين معاً. تنام جميع المتصلين لنفس الفترة الزمنية. تستيقظ جميع المتصلين معاً وتضغط على التبعية مرة أخرى.
ما يتضمنه منطق إعادة المحاولة الأفضل
عادة ما يجمع سلوك الإعادة الجيد بين:
- تأخير أسي
- ذبذبة
- ميزانية إعادة محاولة قصوى
على سبيل المثال:
function backoffMs(attempt: number) {
const base = 250 * 2 ** attempt;
const jitter = Math.random() * 0.3 * base;
return Math.min(base + jitter, 5000);
}
النقطة ليست الأناقة الرياضية. النقطة هي إيقاف الآلاف من العملاء عن إعادة المحاولة في تناغم.
المقايضة
تعد المحاولات ذات معنى فقط للأخطاء التي من المحتمل أن تكون مؤقتة. وغالباً ما تكون غير صحيحة بالنسبة لـ:
- أخطاء التحقق من الصحة
- أخطاء التفويض الدائمة
- الطلبات التي تكون غير آمنة للتكرار بدون قوة مطابقة
هذا هو السبب في أن سياسة إعادة المحاولة وسياسة القوة المطابقة يجب أن تكون معاً.
قراءة إضافية