Resilience לשירותים חיצוניים
למה שכבה מרוכזת?
המעבר למודול resilience.py יוצר אחידות: כל קריאה החוצה עוברת דרך אותה מדיניות Retry + Circuit Breaker.
התוצאה: פחות רעשים זמניים, ניטור ברור יותר, ויכולת להבין בזמן אמת מתי שירות חוץ ”שורף“ אותנו.
איך זה עובד?
RetryPolicy: כמה ניסיונות חוזרים, ו‑Backoff אקספוננציאלי עם
jitterלמניעת ”עדר“.CircuitBreaker: פתיחה/half-open/סגירה לפי כשלים רצופים וחלונות הצלחה.
כל הקביעות נשלטות דרך ENV, ללא שינוי קוד.
דיאגרמת טיפול בשגיאות
התרשים הבא מציג את הזרימה המלאה של טיפול בשגיאות ושחזור:
graph TD
E[Error Occurs] --> ET{Error Type}
ET -->|Database| DBE[DB Error Handler]
ET -->|API| APE[API Error Handler]
ET -->|Timeout| TE[Timeout Handler]
ET -->|Unknown| UE[Generic Handler]
DBE --> RT1{Retry?}
RT1 -->|Yes| RTC1[Retry with Backoff]
RT1 -->|No| FO1[Failover to Cache]
APE --> RT2{Rate Limited?}
RT2 -->|Yes| BK[Activate Backoff]
RT2 -->|No| RTC2[Retry Request]
TE --> CX[Cancel Operation]
CX --> NF[Notify User]
UE --> LOG[Log Error]
LOG --> ALT[Alert Admin]
RTC1 --> SR{Success?}
RTC2 --> SR
FO1 --> SR
BK --> SR
SR -->|Yes| RES[Return Result]
SR -->|No| ERR[Return Error]
סוגי שגיאות והטיפול:
Database Errors: ניסיון חוזר עם Backoff, או Failover ל-Cache
API Errors: בדיקת Rate Limit, הפעלת Backoff או Retry
Timeout Errors: ביטול הפעולה והודעה למשתמש
Unknown Errors: לוגים + התראה לאדמין
עקרונות מרכזיים:
זיהוי סוג השגיאה לטיפול מותאם
Retry עם Backoff אקספוננציאלי למניעת עומס
Failover אוטומטי לשירותי גיבוי (Cache)
התראות לאדמין בשגיאות קריטיות
קונפיגורציה חשובה (ENV)
משתנה |
ברירת מחדל |
מה הוא עושה |
|---|---|---|
|
|
ניסיונות חזרה לפני שמפסיקים |
|
|
זמן ההמתנה הראשון (שניות) לפני כניסה לאקספוננט |
|
|
תקרת ההמתנה בין ניסיונות |
|
|
רעש אקראי (שניות) לכל המתנה |
|
|
כמה כשלונות לפני פתיחת Circuit |
|
|
כמה זמן ממתינים עד ניסיון half-open |
|
|
כמה הצלחות רצופות נדרשות כדי לסגור Circuit |
|
|
חלון לחישוב אחוזי הצלחה |
טיפ
אם שירות חוץ מתחיל להחזיר 429, ניתן זמנית להגדיל CIRCUIT_BREAKER_RECOVERY_SECONDS כדי למנוע עומס חוזר.
שימוש בקוד
כברירת מחדל, כל הקריאות דרך http_sync.request ו‑http_async.request עובדות עם המדיניות הזו. ניתן להעביר
שמות שירות/נתיב לקבלת מטריקות נקיות.
from http_sync import request
resp = request(
"GET",
"https://status.github.com/api",
service="github",
endpoint="status_api",
)