عقدة HTTP Request ترجع أخطاء 429

أقوم بإجراء استدعاءات API متعددة باستخدام عقدة HTTP Request، لكن بعد فترة من الوقت أبدأ في الحصول على أخطاء 429 Too Many Requests. ما أفضل طريقة للتعامل مع حدود معدل API.

مرحباً @Victory1، بينما تنتظر الرد، إليك بعض الأشياء التي قد تساعدك:

الموارد المقترحة

تم مطابقتها تلقائياً مع سؤالك.

المستندات:

المنتدى:

@Yo_its_prakash، @MutedJam، @Niffzy - لقد ساعدتم في مشاكل مشابهة من قبل، هل يمكنكم إلقاء نظرة؟

اقتراح تلقائي من بوت مجتمع n8n. إنه برنامج تجريبي - يرجى مشاركة ملاحظاتك هنا.

تحكم في سرعة طلباتك لتجنب إرهاق نقطة نهاية API.
أضف وقت انتظار كافٍ

خطأ 429 يعني أنك تجاوزت حد الطلبات المسموح به في واجهة برمجية التطبيقات.

حاول إضافة عقدة Wait بين الطلبات، أو معالجة العناصر على دفعات باستخدام Loop Over Items (Batching)، أو تطبيق منطق إعادة المحاولة مع التراجع الأسي.

من الجدير أيضًا التحقق من توثيق واجهة برمجية التطبيقات للحصول على إرشادات حد معدل الطلبات لتجنب الفشل غير الضروري.

مرحباً @Victory1

تمييز صغير لكن مهم بناءً على ما سبق — عقدة HTTP Request لها خيار Batching خاص بها، وهو شيء مختلف عن Loop Over Items batching ولا يتطلب عقد إضافية:

1. HTTP Request → Options → Add Option → Batching
Items per Batch 1، Batch Interval 1000 = طلب واحد/ثانية. بدون Loop Over Items، بدون عقدة Wait، بدون إعادة تسلك.

2. نقطتان مهمتان يجب معرفتهما

  • داخل دفعة واحدة، الطلبات تُرسل بالتوازي — Items per Batch 10 يعني 10 اتصالات متزامنة، وليس 10 متباعدة. أبقِها عند 1 إذا كان API يحد التزامن.
  • إعادة المحاولة المدمجة في n8n Retry On Fail هي فترات ثابتة وتتجاهل Retry-After — لذا فهي ليست exponential backoff. للحصول على backoff حقيقي تحتاج إلى حلقة IF + Wait تقرأ الرأس بنفسك.

3. حدد أي حد تصطدم به أولاً
سجل x-ratelimit-limit / -remaining / -reset من استجابة ناجحة:

  • burst في الثانية الواحدة → التحكم في السرعة يصلحها
  • حصة يومية → التحكم في السرعة لن يساعد، تحتاج إلى عدد أقل من الاستدعاءات
  • حد التزامن → فقط Items per Batch 1 يصلحها

نفس 429، ثلاث مشاكل مختلفة.

4. إذا كان سير العمل يعمل عدة مرات بالتوازي
التحكم في السرعة داخل تنفيذ واحد لن يساعد — كل تشغيل ينتظر بأدب والتشغيلات معاً تغمر API. Self-hosted: N8N_CONCURRENCY_PRODUCTION_LIMIT=1.

أي API هو؟ يسعدني أن أكون أكثر تحديداً.

مرحبا @Victory1
إذا كان لدى API نقطة نهاية جماعية أو دفعية، فيمكن تقليل عدد الطلبات نفسه. ضع عقدة Aggregate قبل عقدة HTTP Request مع تعيين Aggregate إلى All Item Data، وستصل المجموعة بأكملها كعنصر واحد تحت data. ارجع إليها في نص JSON:

{{ JSON.stringify($json.data) }}

بعد ذلك يخرج خمسون عنصرا كطلب واحد بدلا من خمسين طلب.

انهيار جيد من @Hammad_gaming. ملء الجزء الذي أشار إليه لكن لم ينشئه، بالإضافة إلى فئة واحدة من 429 لم يعالجها أي مما سبق.

حلقة Retry-After، لأنها تم ذكرها لكن لم تُعرض

عقدة HTTP Request: أطفئ Retry On Fail، وعيّن Options > Response > Never Error = true. تحتاج إلى أن يعود 429 كبيانات، وليس كخطأ مرفوع، أو لن تتمكن من قراءة الرأس.

ثم IF على {{ $json.statusCode }} يساوي 429 → عقدة Code لحساب الانتظار → عقدة Wait → ارجع إلى عقدة HTTP.

عقدة Code:

const h = $json.headers || {};
let sec = 1;

if (h[‘retry-after’]) {
const v = h[‘retry-after’];
// Retry-After إما delta-seconds أو HTTP-date
sec = isNaN(v) ? Math.max(0, (new Date(v) - Date.now()) / 1000)
: Number(v);
} else if (h[‘x-ratelimit-reset’]) {
const r = Number(h[‘x-ratelimit-reset’]);
// بعض APIs ترسل epoch seconds، والبعض الآخر يرسل seconds-remaining
sec = r > 1e9 ? r - Math.floor(Date.now() / 1000) : r;
} else {
const n = $runIndex || 0;
sec = Math.min(2 ** n, 60);
}

// jitter — هذا السطر أهم مما يبدو
sec = sec * (0.5 + Math.random() * 0.5);

return [{ json: { waitSeconds: Math.ceil(sec) } }];

ثلاثة أشياء فيها من السهل تفويتها:

Retry-After مسموح به أن يكون HTTP-date وليس فقط عدد الثواني. تحليله كعدد صحيح يعطيك صامتًا NaN وانتظار بدون ثوان، لذلك تعيد المحاولة فورًا وتحصل على 429 مرة أخرى.

x-ratelimit-reset غير متسق عبر APIs — GitHub يرسل epoch seconds، والبعض الآخر يرسل seconds-remaining. فحص الحجم يتعامل مع كليهما.

سطر jitter هو الذي يتخطاه الناس. بدونه، إذا كان لديك 20 عنصرًا يضربان جميعًا 429 في نفس اللحظة، فإنهم جميعًا ينتظرون بالضبط نفس المدة وجميعهم يعيدون المحاولة في نفس اللحظة. أعدت بناء المشكلة الأصلية بخطوة إضافية. تعشيش الانتظار ينتشر بها.

عاصفة إعادة المحاولة، التي لا يحلها التنظيم

يستحق أن تكون صريحًا: Retry On Fail يعيد محاولة كل عنصر. خمسون عنصرًا، ثلاث محاولات لكل واحد، و 429 يضرب في العنصر 20 يعني أنه يمكنك إطلاق 90 طلبًا إضافيًا في API أخبرك بالتوقف. بعض APIs تستجيب لذلك بتمديد الحجب.

إذا كنت تستخدم Retry On Fail على دفعة، عيّن Max Tries على 2 والتعامل مع إعادة المحاولة الفعلية بالحلقة أعلاه، حيث التنظيم تحت سيطرتك.

الواحد لم يذكره أحد: حدود الرموز، وليس حدود الطلبات

@Victory1 — إذا كان هذا OpenAI أو Anthropic أو Cohere أو أي API LLM، هناك احتمال جيد بأنك لا تضرب حد الطلب على الإطلاق.

هؤلاء المزودون يفرضون حدين منفصلين: طلبات في الدقيقة ورموز في الدقيقة. TPM عادةً ما تكون هي التي تضربها أولاً، وأي من نصائح التنظيم أعلاه لا تلمسها، لأن القيد هو حجم الحمل وليس تكرار الاستدعاء.

العرض الذي يخبرك أيهما: إذا أصبح 429s أسوأ عندما تصبح مستنداتك أطول، لكن عدد الاستدعاءات لم يتغير، إنه TPM.

الإصلاحات مختلفة أيضًا — تقلل الرموز بدلاً من الإبطاء. قص المطالبة، اسقط max_tokens إذا كنت قد عينتها عالية (بعض المزودين يعدون الحجز مقابل ميزانيتك وليس الإخراج الفعلي)، اقسم المستندات الطويلة، أو أرسل الاستدعاءات القصيرة إلى نموذج أصغر.

رؤوس الاستجابة تسميها مباشرة إذا سجلت بها:
x-ratelimit-remaining-requests مقابل x-ratelimit-remaining-tokens.
أيهما يضرب صفر أولاً هو حدك الفعلي.

وواحد يهدر بعد الظهر

بعض APIs لا ترجع 429 على الإطلاق. نقطة Shopify GraphQL تعود 200 بحالة اختناق داخل الجسم. وكذلك أكثر من مزود دفع واحد.

إذا كان سير العمل الخاص بك “لا يخطئ” لكن البيانات مفقودة بصمت، تحقق من جسم الاستجابة بدلاً من رمز الحالة. IF على statusCode لن يمسكها أبدًا.

ما API؟ الإصلاح الصحيح مختلف لكل من الحالات الثلاث.