بناء مُزخرف retry
Build a Retry Decorator
بناء مُزخرف retry — Build a Retry Decorator
في التطوير الحقيقي، العمليات تفشل: طلبات الشبكة تنتهي مهلتها، قواعد البيانات تكون مشغولة، الخدمات الخارجية تتعطل. الحل الاحترافي هو الإعادة التلقائية عند الفشل (Retry) — وأفضل مكان لهذا المنطق هو مُزخرف قابل للإعادة الاستخدام.
ستبني هذا المُزخرف خطوة بخطوة، بدءاً من النسخة الأبسط ووصولاً لنسخة إنتاجية متكاملة. كل خطوة تبني على السابقة.
الخطوة 1 — مُزخرف بسيط (بدون إعداد)
أولاً، نبني مُزخرفاً يُعيد المحاولة مرتين إضافيتين عند أي فشل — من غير معاملات (لا factory بعد).
المُزخرف يلتقط Exception، يطبع رسالة، ويُعيد المحاولة. إذا استنفد كل المحاولات يُعيد إطلاق آخر خطأ لكي يُعالجه المستدعي.
الخطوة 2 — decorator factory مع times
المُزخرف الثابت غير مرن. نريد @retry(times=5). هذا يتطلب decorator factory — دالة تُنتج مُزخرفاً.
الخطوة 3 — الإمساك بالاستثناء والإعادة الصحيحة
بنينا الهيكل. الآن نتأكد أن المُزخرف يُعيد رمي الاستثناء إذا استنفدت كل المحاولات، ولا يبتلع الخطأ صامتاً.
الخطوة 4 — إضافة Backoff أسّي
إعادة المحاولة فوراً قد تُرهق الخادم. في الإنتاج نضيف تأخير يتضاعف بعد كل فشل: 1s، 2s، 4s…
الخطوة 5 — تصفية الاستثناءات
أحياناً تريد الإعادة فقط عند استثناءات معينة. خطأ ValueError (بيانات خاطئة) لا يستحق إعادة — أما ConnectionError فيستحق.
النسخة الكاملة — Full Production Version
الآن نجمع كل الخطوات في مُزخرف واحد إنتاجي:
الخلاصة — Summary
المُزخرف retry الذي بنيته يجسّد كل ما تعلمته في هذا الفصل:
- الدوال كقيم —
decoratorتأخذfnوتُرجعwrapper - decorator factory —
retry(times, delay, ...)تُنتج مُزخرفاً قابلاً للإعداد functools.wraps— يحفظ اسم ووثائق الدالة الأصلية*args, **kwargs— يجعل wrapper مرناً مع أي توقيع- Type hints — توثيق واضح لكل معامل ونوعه
- معالجة الاستثناءات — التمييز بين ما يستحق الإعادة وما لا يستحق
هذا النمط موجود في مكتبات Python الشهيرة: tenacity، backoff، retry، وurllib3. الآن تفهم كيف تبنيه من الصفر — وهذا أهم من حفظ API مكتبة.