المقدمة
في تطوير البرمجيات، تعتبر منطق إعادة المحاولة الموثوقة ضرورية للتعامل مع الفشل المتقطع، مثل مشاكل الشبكة أو الانقطاعات المؤقتة. مؤخرًا، صادفت قاعدة شفرة استخدم فيها مطور حلقة for
مع فترة زمنية ثابتة لإعادة محاولة العمليات الفاشلة. على الرغم من أن هذه الطريقة قد تبدو بسيطة، إلا أنها تفتقر إلى المرونة اللازمة للتطبيقات في العالم الحقيقي. وهنا تأتي أهمية تقنية التراجع الأسّي – استراتيجية تهدف إلى جعل إعادة المحاولة أكثر ذكاءً وكفاءة.
في هذه المقالة، سنستعرض كيف تعمل تقنية التراجع الأسّي، ومزاياها مقارنةً بحلقة إعادة المحاولة الأساسية، وكيف يمكنك تنفيذها لتعزيز موثوقية نظامك. سأرشدك أيضًا من خلال مثال عملي باستخدام وحدة إرسال البريد الإلكتروني، موضحًا لك كيفية استخدام التراجع الأسّي لضمان معالجة الأخطاء بشكل أكثر مرونة.
ما هو التراجع الأسّي؟
التراجع الأسّي هو استراتيجية لإعادة المحاولة حيث تزداد فترة الانتظار بين محاولات إعادة المحاولة بشكل أسّي بعد كل فشل. بدلاً من إعادة المحاولة في فترات ثابتة، تنتظر كل محاولة لاحقة لفترة أطول من سابقتها – عادةً ما تضاعف الوقت المستغرق في كل مرة. على سبيل المثال، إذا كانت فترة التأخير الأولية هي 1 ثانية، ستحدث المحاولات التالية في 2، 4، 8 ثوانٍ، وهكذا. تساعد هذه الطريقة في تقليل الضغط على النظام وتقليل خطر إغراق الخدمات الخارجية خلال فترات الطلب العالية.
من خلال السماح بمزيد من الوقت بين عمليات إعادة المحاولة، يمنح التراجع الأسّي القضايا المؤقتة فرصة للحل، مما يؤدي إلى معالجة أخطاء أكثر كفاءة وتحسين استقرار التطبيق.
مزايا وعيوب التراجع الأسّي
المزايا:
-
تقليل الحمل على النظام: من خلال توزيع المحاولات المتكررة، يقلل أسلوب التراجع الأسي من فرصة إغراق الخوادم، مما يكون مفيدًا بشكل خاص في التعامل مع حدود المعدلات أو الانقطاعات المؤقتة.
-
معالجة الأخطاء بكفاءة: يسمح التأخير المتزايد للمشاكل المؤقتة بمزيد من الوقت للحل بشكل طبيعي، مما يحسن من احتمالية النجاح في المحاولة المتكررة.
-
تحسين الاستقرار: خاصةً للأنظمة ذات الحركة العالية، يمنع تدفق محاولات التكرار، مما يحافظ على سير التطبيقات بسلاسة دون استهلاك مفرط للموارد.
العيوب:
- زيادة التأخير: مع كل محاولة متكررة تأخذ وقتًا أطول، يمكن أن يؤدي التراجع الأسي إلى تأخيرات، خاصةً إذا كانت هناك حاجة للعديد من المحاولات قبل النجاح.
حالات الاستخدام الرئيسية للتراجع الأسي
يكون التراجع الأسي مفيدًا بشكل خاص في السيناريوهات التي تتفاعل فيها الأنظمة مع خدمات خارجية أو تدير كميات كبيرة من الحركة. إليك بعض حالات الاستخدام الشائعة الأخرى:
-
واجهات برمجة التطبيقات المحدودة المعدل: بعض واجهات برمجة التطبيقات لديها حدود للطلبات، مما يقيّد الطلبات خلال فترة زمنية معينة. يساعد التراجع الأسي في تجنب المحاولات الفورية التي قد تتجاوز الحد، مما يتيح الوقت لإعادة تعيين الحد.
-
عدم استقرار الشبكة: في حالات فشل الشبكة المؤقتة أو انتهاء المهلة، يساعد التراجع الأسي من خلال الانتظار لفترة أطول بين المحاولات، مما يسمح للشبكة بالاستقرار.
-
اتصالات قاعدة البيانات: عند الاتصال بقاعدة البيانات تحت حمل ثقيل، يساعد التراجع الأسي في منع المزيد من التحميل الزائد عن طريق تأخير المحاولات، مما يمنح قاعدة البيانات الوقت للتعافي.
-
أنظمة الطوابير: في أنظمة الطوابير الرسائل، إذا فشلت رسالة بسبب خطأ، يمكن أن يساعد استخدام التراجع الأسي لإعادة المحاولات في منع إعادة المعالجة السريعة ويسمح بوقت لحل المشكلات المؤقتة.
بناء خدمة إرسال بريد إلكتروني أساسية مع التعزيز الأسي
لإظهار التعزيز الأسي، سنقوم ببناء مرسل بريد إلكتروني أساسي يعيد محاولة إرسال الرسائل إذا حدث خطأ. هذه المثال يوضح كيف يحسن التعزيز الأسي عملية إعادة المحاولة مقارنةً بدورة بسيطة.
import nodemailer from "nodemailer";
import { config } from "../common/config";
import SMTPTransport from "nodemailer/lib/smtp-transport";
const emailSender = async (
subject: string,
recipient: string,
body: string
): Promise<boolean> => {
const transport = nodemailer.createTransport({
host: config.EMAIL_HOST,
port: config.EMAIL_PORT,
secure: true,
auth: { user: config.EMAIL_SENDER, pass: config.EMAIL_PASSWORD },
} as SMTPTransport.Options);
const mailOptions: any = {
from: config.EMAIL_SENDER,
to: recipient,
subject: subject,
};
const maxRetries = 5; // maximum number of retries before giving up
let retryCount = 0;
let delay = 1000; // initial delay of 1 second
while (retryCount < maxRetries) {
try {
// send email
await transport.sendMail(mailOptions);
return true;
} catch (error) {
// Exponential backoff strategy
retryCount++;
if (retryCount < maxRetries) {
const jitter = Math.random() * 1000; // random jitter(in seconds) to prevent thundering herd problem
const delayMultiplier = 2
const backOffDelay = delay * delayMultiplier ** retryCount + jitter;
await new Promise((resolve) => setTimeout(resolve, backOffDelay));
} else {
// Log error
console.log(error)
return false; // maximum number of retries reached
}
}
}
return false;
};
ضبط معلمات التعزيز الأسي
يتضمن تنفيذ التعزيز الأسي ضبط بعض المعلمات للتأكد من أن استراتيجية إعادة المحاولة تعمل بشكل جيد لتلبية احتياجات تطبيقك. المعلمات الرئيسية التالية تؤثر على سلوك وأداء التعزيز الأسي في آلية إعادة المحاولة:
- التأخير الأولي
-
الغرض: يحدد وقت الانتظار قبل أول محاولة. يجب أن يكون طويلًا بما يكفي لمنع المحاولات الفورية ولكنه قصير بما يكفي لتجنب التأخيرات الملحوظة.
-
الإعداد الموصى به: ابدأ بتأخير يتراوح بين 500 مللي ثانية إلى 1000 مللي ثانية. بالنسبة للأنظمة الحرجة، استخدم تأخيرًا أقصر، بينما يمكن أن تحتوي العمليات الأقل إلحاحًا على تأخير أطول.
- مضاعف التأخير
-
الغرض: يتحكم في سرعة زيادة التأخير بعد كل محاولة إعادة. مضاعف 2 يضاعف التأخير (مثل: 1 ثانية، 2 ثانية، 4 ثواني).
-
الإعداد الموصى به: عادةً، مضاعف بين 1.5 و 2 يوازن بين الاستجابة والثبات. المضاعفات الأعلى (مثل: 3) قد تكون مناسبة إذا كان النظام يمكنه التعامل مع تأخيرات أطول بين المحاولات.
- الحد الأقصى لمحاولات الإعادة
-
الغرض: يحد من محاولات الإعادة لمنع المحاولات المفرطة التي يمكن أن تستنزف الموارد أو تزيد من حمل النظام.
-
الإعداد الموصى به: عادةً ما تكون نطاق 3 إلى 5 محاولات كافية لمعظم التطبيقات. بعد ذلك، قد تحتاج العملية إلى تسجيلها كفاشلة أو إدارتها بشكل مختلف، مثل إبلاغ المستخدم أو تفعيل تنبيه.
- التخفيض العشوائي (التعويض)
-
الغرض: يضيف عشوائية إلى كل تأخير لمنع تراكم المحاولات وإحداث تأثير القطيع الرعدي.
-
الإعداد الموصى به: أضف تأخيرًا عشوائيًا بين 0 و 500 مللي ثانية إلى كل فترة محاولة إعادة. يساعد هذا التخفيض في توزيع محاولات إعادة الاتصال بشكل أكثر توازنًا على مر الزمن.
الخاتمة
من خلال استخدام التعويض الأسي، تضيف مرونة إلى تطبيقك، مما يجعله مستعدًا للتعامل مع المشكلات غير المتوقعة. إنها تغيير صغير له تأثير كبير، خاصة مع نمو تطبيقك.
وهذا كل شيء في الوقت الحالي، يا أصدقاء. لا تترددوا في ترك تعليق، واسألوا أي سؤال إذا كان لديكم. لنستمتع ببناء تطبيقات أكثر موثوقية ومرونة.
تمنيات بالتوفيق في البرمجة! 👨💻❤️
Source:
https://timothy.hashnode.dev/implementing-exponential-backoff-for-reliable-systems