T1 · Intermediate · 9 دقيقةثابت · آخر مراجعة: 2026-08-19مسودة أولى — بنراجعها

الأخطاء والـ Retries — لمّا الـ call يقع

في سطر واحد · الـ API بيقع أحيانًا (نت، ضغط، خطأ مؤقت)، والحل إنك تفرّق بين الغلطة اللي تعيدها والغلطة اللي متعيدهاش، وتعيد بذكاء.

القاموس:BackoffInferenceJitterModelTrace
ليه ده مهم؟

منتج بيقع مع أول error مش هيعيش في production. التعامل الصح مع الأخطاء هو اللي بيخلّي service «شغّال» يبقى service «موثوق».

زي ما بتضرب تليفون ومش بيرد: لو مشغول تعيد بعد شوية (مؤقت)، بس لو الرقم غلط أصلًا مفيش فايدة تعيد ألف مرة. الأخطاء نفس الفكرة.

خلينا نفهمها بمثال

الـ backoff مع jitter زي جمهور اتقفل في وشّه باب: لو كلهم زنّوا على الباب في نفس اللحظة، هيفضل مقفول. لكن لو كل واحد استنّى مدة مختلفة شوية قبل ما يدق تاني، الزحمة بتتفكّ والباب بيفتح.

code زي 429 أو 503 (أو انقطاع نت) معناه «حاول تاني بعد شوية» فتعيد بـ exponential backoff مع jitter — كل محاولة تستنّى أطول شوية + رقم عشوائي عشان الكلاينتات ما ترجعش كلها في نفس اللحظة؛ لكن 400 أو 401 غلط دايم (مفتاح غلط / request باظ) — تعيده مش هيصلّح حاجة، لازم تظبط المشكلة نفسها.

طيب بتحصل إزاي؟

أول خطوة تصنيف الخطأ: 429 و503 وانقطاع النت أخطاء مؤقتة (transient) تتعاد؛ 400 و401 أخطاء دايمة (permanent) — الإعادة مش هتصلّحها، لازم تصلّح الـ request أو المفتاح. الإعادة بتبقى بـ exponential backoff: كل محاولة تستنّى ضعف اللي قبلها + jitter عشوائي عشان الكلاينتات ما ترجعش كلها في نفس اللحظة. لو السيرفر بعت header Retry-After بتحترمه وتستنّى المدة اللي قالها بالظبط، وبتحطّ سقف للمحاولات (٣–٥) عشان العطل الحقيقي يفشل بشكل نضيف بدل ما يعلّق.

async function callWithRetry(fn, maxAttempts = 4) {
  for (let attempt = 0; ; attempt++) {
    try {
      return await fn();
    } catch (err) {
      const transient =
        err.status === 429 || err.status === 503 || err.code === "ECONNRESET";
      if (!transient || attempt >= maxAttempts - 1) throw err; // 400/401: fail fast
      const retryAfterMs = Number(err.headers?.["retry-after"]) * 1000 || 0;
      const backoffMs = 500 * 2 ** attempt + Math.random() * 300; // jitter
      await sleep(Math.max(retryAfterMs, backoffMs));
    }
  }
}
خلينا نبنيها

🧪 جرّب بنفسك: اكتب دالة callWithRetry بتعيد بس على 429/503/انقطاع النت، بـ exponential backoff + jitter وسقف ٤ محاولات، وبتحترم Retry-After لو موجود. جرّبها على mock server بيرجع 429 مرّتين وبعدين 200 — وبيرجع 401 عشان تتأكد إنها بتفشل فورًا.

أشهر الأخطاء

(١) تعيد الـ 401 في loop — بتحرق وقت وrequests على خطأ عمره ما هينجح؛ المفتاح غلط، صلّحه. (٢) delay ثابت من غير jitter — كل الكلاينتات بترجع في نفس اللحظة فبتعمل موجة ضغط جديدة (thundering herd). (٣) تتجاهل Retry-After وتخمّن من دماغك — السيرفر قالك بالظبط تستنّى قد إيه.

إمتى تستخدمها؟

كل network call لـ AI API في البرودكشن — اكتب helper واحد للـ retry واستخدمه في كل مكان بدل ما تكرّر المنطق.

وإمتى لأ؟

متعيدش الأخطاء الدايمة (400/401/403) أبدًا، ومتعيدش طلب ليه side effect (خصم، إيميل) من غير idempotency key — ممكن يتنفّذ مرّتين (شوف درس الـ timeouts والـ idempotency).

خلينا نبنيهاالقراءة خلصت — دلوقتي ابنيها بإيدك.اعمل retry بـ exponential backoff