التكامل الآمن مع مزوّدي الطرف الثالث ليبقي تطبيقك يعمل أثناء الانقطاعات. تعلّم عن المهلات، إعادة المحاولات، قواطع الدائرة، والتحقّقات السريعة.

يمكن أن تفشل واجهة برمجة طرف ثالث بطرق لا تبدو كحدث "تعطّل" واضح. المشكلة الأكثر شيوعًا هي البطء: الطلبات تتعطل، الاستجابات تصل متأخرة، وتطبيقك يظل في الانتظار. إذا كانت تلك المكالمات على المسار الحرج، فإن عثرة صغيرة خارج نطاق سيطرتك تتكدس داخل نظامك.
هكذا يتحول تباطؤ محلي إلى تعطل كامل. الخيوط أو العمال يعلقون في الانتظار، الطوابير تنمو، المعاملات على قاعدة البيانات تبقى مفتوحة لفترة أطول، والطلبات الجديدة تبدأ في النفاد. قبل فترة وجيزة، حتى الصفحات التي لا تستخدم الـ API الخارجي تبدو معطلة لأن النظام مثقل بأعمال في الانتظار.
التأثير ملموس. مزود هوية متقلب يعيق التسجيل وتسجيل الدخول. مهلة بوابة الدفع تجمّد إتمام الشراء وتترك المستخدمين غير متأكدين مما إذا تم خصم المال. تأخير في الرسائل يوقف إعادة تعيين كلمات المرور وتأكيدات الطلبات، مما يؤدي إلى موجة ثانية من المحاولات والدعم.
الهدف بسيط: عزل فشل الطرف الخارجي حتى تستمر عملياتك الأساسية. قد يعني ذلك السماح للمستخدم بوضع طلب مع تأكيد الدفع لاحقًا، أو إتمام التسجيل حتى لو فشل إرسال رسالة ترحيب.
مقياس نجاح عملي: عندما يكون المزود بطيئًا أو معطلاً، يجب أن يظل تطبيقك يستجيب بسرعة وبوضوح، ويجب أن يبقى نطاق التأثير صغيرًا. على سبيل المثال، تظل معظم الطلبات الأساسية ضمن ميزان الكمون المعتاد، تبقى الأخطاء محصورة في الميزات التي تعتمد فعليًا على ذلك الـ API، يرى المستخدم حالة واضحة (قيد الانتظار، معلق، أعد المحاولة لاحقًا)، والعودة للعمل التلقائية تحدث عندما يعود المزود.
معظم حالات الفشل متوقعة، حتى لو لم تكن توقيتها معروفًا. اسمّها مقدمًا ويمكنك أن تقرر ما الذي تعيد المحاولة فيه، وما الذي توقفه، وماذا تظهر للمستخدم.
الفئات الشائعة:
ليست كل الأخطاء متماثلة. القضايا المؤقتة غالبًا ما تستحق إعادة المحاولة لأن المحاولة التالية قد تنجح (انقطاعات الشبكة المؤقتة، مهلات، 502/503، وبعض 429s بعد الانتظار). القضايا الدائمة نادرًا ما تُصلح نفسها (بيانات اعتماد غير صالحة، نقاط نهاية خاطئة، طلبات مشوهة، رفض صلاحيات).
معاملة كل خطأ بنفس الطريقة يحول حادثًا صغيرًا إلى تعطل. إعادة المحاولة على الأخطاء الدائمة تهدر الوقت، تضغط حدود المعدل أسرع، وتبني تراكمًا يبطئ كل شيء آخر. عدم إعادة المحاولة على الأخطاء المؤقتة يجبر المستخدمين على تكرار الإجراءات ويفقد عملًا كان يمكن أن يكتمل بعد لحظات.
انتبه بشكل خاص لسير العمل حيث يشعر التوقف ككسر: إتمام الشراء، تسجيل الدخول، إعادة تعيين كلمة المرور، والإشعارات (البريد الإلكتروني/الرسائل القصيرة/الإشعارات الفورية). ارتفاع بمقدار ثانيتين في API تسويقي مزعج؛ نفس الارتفاع في تفويض الدفع يعرقل الإيرادات.
اختبار مفيد: "هل يجب أن تنتهي هذه المكالمة لإنهاء مهمة المستخدم الرئيسية الآن؟" إذا كانت الإجابة نعم، فأنت بحاجة لمهلات ضيقة، وإعادة محاولات محسوبة، ومسار فشل واضح. إذا لا، فحوّلها إلى قائمة ودع التطبيق يظل سريع الاستجابة.
المهلة هي أقصى زمن مستعدون للانتظار قبل الإيقاف والمضي قدمًا. بدون حد واضح، يمكن لمزوّد بطيء أن يكدس طلبات في الانتظار ويمنع العمل المهم.
من المفيد فصل نوعين من الانتظار:
اختيار الأرقام ليس عن الكمال، بل عن مطابقة صبر البشر وسير العمل.
طريقة عملية لاختيار المهلات هي العمل عكسيًا من التجربة:
المقايضة حقيقية. وقت طويل جدًا يربط الخيوط والعمال واتصالات قاعدة البيانات. وقت قصير جدًا يخلق أخطاء وهمية ويطلق محاولات غير ضرورية.
تساعد إعادة المحاولات عندما يكون الفشل غالبًا مؤقتًا: مشكلة شبكة قصيرة، عطل DNS، أو خطأ 500/502/503 لمرة واحدة. في تلك الحالات، قد تنجح المحاولة الثانية ولا يلاحظ المستخدم شيء.
المخاطرة هي عاصفة المحاولات. عندما يفشل العديد من العملاء دفعة واحدة وكلهم يعيدون المحاولة معًا، قد يحمِّلون المزود (ونظامك نفسه). تمنع الاستجابة المتدرجة (backoff) والتشتت العشوائي (jitter) ذلك.
ميزانية إعادة المحاولات تحافظ على انضباطك. اجعل المحاولات قليلة وحدد إجمالي زمن بحيث لا تعلق تدفقات العمل الأساسية في انتظار طرف آخر.
لا تعد المحاولة على أخطاء العميل المتوقعة مثل 400/422 مشاكل التحقق، أو 401/403 مشاكل المصادقة، أو 404s. هذه ستفشل مجددًا وتضيف حملًا فقط.
حاجز آخر: أعد المحاولة للكتابات (POST/PUT) فقط عندما يكون لديك عدم تكرار (idempotency) مفعلًا، وإلا فستخاطر بخصميات مزدوجة أو سجلات مكررة.
عدم التكرار يعني أنه يمكنك تنفيذ نفس الطلب مرتين بأمان والحصول على نفس النتيجة النهائية. هذا مهم لأن إعادة المحاولات عادية: الشبكات تسقط، الخوادم تعيد التشغيل، والعملاء ينفد زمنهم. بدون عدم تكرار، قد تخلق إعادة المحاولة "مضاعفات" ومشاكل مالية حقيقية.
تخيل إتمام الدفع: API الدفع بطئ، تطبيقك انتهت مهلته، فأعدت المحاولة. إذا كانت المكالمة الأولى قد نجحت فعلاً، قد تُنشئ المحاولة الثانية خصمًا ثانيًا. نفس الخطر يظهر في إنشاء طلب، بدء اشتراك، إرسال بريد/رسالة، إصدار رد، أو إنشاء تذكرة دعم.
الحل: أرفق مفتاح عدم التكرار (idempotency key) أو معرف الطلب مع كل مكالمة "نفّذ شيئًا". يجب أن يكون فريدًا لكل فعل مستخدم، ليس لكل محاولة. يستخدم المزود (أو خدمتك الداخلية) ذلك المفتاح لاكتشاف المكررات وإرجاع نفس النتيجة بدلًا من تنفيذ العمل ثانية.
عامل مفتاح عدم التكرار كجزء من نموذج البيانات، وليس كعنوان تأمل ألا ينسى أحد وضعه.
ولِّد مفتاحًا عندما يبدأ المستخدم الفعل (مثلاً عند الضغط على زر الدفع)، ثم خزّنه مع السجل المحلي.
في كل محاولة:
إذا كنت "المزوِّد" للمكالمات الداخلية، فطبّق نفس السلوك على الخادم أيضًا.
قاطع الدائرة هو مفتاح أمان. عندما يبدأ خدمة خارجية في الفشل، تتوقف عن استدعائها لفترة قصيرة بدلًا من تكديس المزيد من الطلبات التي على الأرجح ستنفد مهلاتها.
عادةً ما يكون للقواطع ثلاث حالات:
عندما يكون القاطع مفتوحًا، يجب أن يفعل تطبيقك شيئًا متوقعًا. إذا كان API تحقق العنوان معطلاً أثناء التسجيل، اقبل العنوان وعلّمه للمراجعة لاحقًا. إذا كان فحص مخاطر الدفع معطلاً، ضع الطلب في قائمة للمراجعة اليدوية أو عطّل تلك الخاصية مؤقتًا وفسّر السبب.
اختر عتبات تتماشى مع تأثير المستخدم:
اجعل فترات التهدئة قصيرة (ثوانٍ إلى دقيقة) وحدد اختبارات نصف المفتوح محدودة. الهدف حماية سير العمل الأساسي أولًا، ثم التعافي بسرعة.
عندما يكون API خارجي بطيئًا أو معطلاً، هدفك إبقاء المستخدم يتحرك. هذا يعني وجود خطة بديلة صادقة تشرح ما حدث.
الحل البديل هو ما يفعله تطبيقك عندما لا يستجيب الـ API في الوقت المناسب. الخيارات تشمل استخدام بيانات مخبأة، الانتقال إلى وضع مقطوع (إخفاء عناصر غير أساسية، تعطيل إجراءات اختيارية)، طلب إدخال يدوي من المستخدم بدلًا من استدعاء الـ API (إدخال العنوان يدويًا)، أو عرض رسالة واضحة مع الخطوة التالية.
كن صادقًا: لا تقل إن شيئًا اكتمل إن لم يحدث.
إذا لم تكن المهمة بحاجة للإتمام ضمن طلب المستخدم، ادفعها إلى قائمة (queue) ورد بسرعة. المرشحين الشائعين: إرسال رسائل البريد الإلكتروني، المزامنة مع CRM، توليد تقارير، وإرسال أحداث تحليلية.
افشل بسرعة للإجراءات الأساسية. إذا لم يكن API ضروريًا لإكمال الدفع (أو إنشاء الحساب)، لا تعطل الطلب. اقبل الطلب، ضع استدعاء الـ API في قائمة، ووافق عليه لاحقًا. إذا كان الـ API ضروريًا (مثلاً تفويض الدفع)، افشل بسرعة برسالة واضحة ولا تجعل المستخدم ينتظر.
ما يراه المستخدم يجب أن يتطابق مع ما يحدث خلف الكواليس: حالة واضحة (مكتمل، معلق، فشل)، وعد يمكنك الوفاء به (إيصال الآن، تأكيد لاحقًا)، طريقة لإعادة المحاولة، وسجل مرئي في الواجهة (سجل النشاط، شارة معلق).
حدود المعدل (rate limits) طريقة المزود ليقول: "يمكنك استدعاؤنا، لكن ليس بسرعة كبيرة." ستصطدم بها أسرع مما تتوقع: طفرات حركة المرور، مهام خلفية تتزامن، أو خطأ يتسبب في حلقة على الأخطاء.
ابدأ بالتحكم في عدد الطلبات التي تنشئها. جمع الدُفعات عند الإمكان، خزّن الاستجابات مؤقتًا حتى 30–60 ثانية عندما يكون ذلك آمنًا، وحدّ العميل حتى لا ينفجر التطبيق أسرع مما يسمح المزود.
عند الحصول على 429 Too Many Requests تعامل معها كإشارة للإبطاء.
Retry-After عندما يُقدّم.حدّ أيضًا التزامن. سير عمل واحد (مثل مزامنة جهات الاتصال) لا يجب أن يستهلك كل فتحات العمال ويجوع تدفقات حاسمة مثل تسجيل الدخول أو الدفع. تجمعات منفصلة أو حدود لكل ميزة تساعد.
كل استدعاء لطرف ثالث يحتاج خطة لفشل. لا تحتاج للكمال، تحتاج سلوكًا متوقعًا عندما يكون للمزود يوم سيئ.
قرّر ماذا يحدث إذا فشل الاستدعاء الآن. حساب الضريبة أثناء إتمام الشراء قد يكون ضروريًا. مزامنة جهة تسويق عادةً يمكن أن تنتظر. هذا الاختيار يحدد الباقي.
اختر مهلات لكل نوع مكالمة واحتفظ بها متسقة. ثم حدّ ميزانية إعادة المحاولات حتى لا تستمر في ضرب الـ API البطيء.
إذا كان الطلب قد ينشئ شيئًا أو يخصم مالًا، أضف مفاتيح عدم التكرار وخزن سجل الطلب. إذا انتهت مهلة طلب الدفع، يجب ألا تكرّر المحاولة وتخصم مرتين. التتبع يساعد الدعم الإجابة: "هل تم التنفيذ؟"
عندما ترتفع الأخطاء، توقف عن استدعاء المزود لفترة قصيرة. للاستدعاءات الضرورية اعرض مسار "أعد المحاولة" واضحًا. للمهام القابلة للانتظار ضع العمل في قائمة وتعامل معه لاحقًا.
تتبّع الكمون، معدل الأخطاء، وأحداث فتح/إغلاق القواطع. نبه عند تغيّرات مستمرة، لا على نفحات بسيطة.
معظم انقطاعات الـ API لا تبدأ كبيرة. تكبر لأن تطبيقك يتصرف بطريقة سيئة: ينتظر طويلًا، يعيد المحاولة بعنف، ويربط نفس العمال الذين تُشغل كل شيء الآخر.
هذه الأنماط تسبب تسلسلات كارثية:
إصلاحات بسيطة تمنع انقطاعات كبيرة: أعد المحاولة فقط على الأخطاء المحتملة أن تكون مؤقتة (مهلات، بعض 429s، بعض 5xx) وحدّ المحاولات مع backoff وjitter؛ اجعل المهلات قصيرة ومتعمدة؛ اجعل عدم التكرار مطلوبًا لكل عملية تنشئ أو تخصم؛ وصمّم لتدهور جزئي.
قبل الدفع بالتكامل إلى الإنتاج، قم بمراجعة سريعة بعقلية فشل. إذا لم تستطع أن تجيب بـ"نعم" على بند، اعتبره مانع إصدار لسير العمل الأساسي مثل التسجيل، الدفع، أو إرسال الرسائل.
إذا بدأ مزود الدفع في الانقضاء، السلوك الصحيح هو "لا يزال تحميل صفحة الدفع، المستخدم يرى رسالة واضحة، ولا نبقى في حلقة انتظار"، وليس "كل شيء يتعطل حتى تنتهي المهلات."
تخيل صفحة دفع تستدعي ثلاث خدمات: API للدفع لخصم البطاقة، API للضرائب لحساب الضريبة، وAPI للبريد لإرسال الإيصال.
مكالمة الدفع هي الوحيدة التي يجب أن تكون متزامنة. مشاكل الضريبة أو البريد لا يجب أن توقف الشراء.
افترض أن API الضرائب أحيانًا يستغرق 8–15 ثانية. إذا انتظرت صفحة الدفع، يهجر المستخدمون سلاتهم ويتكدس العمال.
تدفق أكثر أمانًا:
النتيجة: سلات مهجورة أقل وأوامر عالقة أقل عندما يكون مزود الضرائب بطيئًا.
بريد الإيصال مهم، لكنه لا يجب أبدًا أن يعيق تحصيل الدفع. إذا كان API البريد يفشل، يجب أن يفتح قاطع الدائرة بعد عدة فشلات سريعة ويوقف المكالمات لفترة قصيرة.
بدلاً من إرسال البريد داخل الطلب، ضع مهمة "إرسال إيصال" في قائمة مع مفتاح عدم تكرار (مثلاً order_id + email_type). إذا كان المزود معطلاً، تعيد القائمة المحاولة في الخلفية ويبقى العميل يرى شراءً ناجحًا.
النتيجة: تذاكر دعم أقل بسبب الإيصالات المفقودة، ولا خسارة في الإيرادات لأن الدفع لا يفشل لأسباب غير متعلقة بالدفع.
اختر سير عمل واحد يسبب أكبر ألم عند تعطلِه (الشراء، التسجيل، الفوترة) واجعله تكاملك المرجعي. ثم انسخ الإعدادات الافتراضية نفسها في كل مكان.
ترتيب نشر بسيط:
دوّن إعداداتك الافتراضية واحتفظ بها مملة: مهلة اتصال واحدة، مهلة طلب واحدة، أقصى عدد محاولات، نطاق backoff، فترة تهدئة للقاطع، وقواعد ما يمكن إعادة المحاولة.
قم بتشغيل تمرين فشل قبل التوسيع إلى سير العمل التالي. فرض مهلات (أو حجب المزود في بيئة اختبار)، ثم تأكد أن المستخدم يرى رسالة مفيدة، أن المسارات البديلة تعمل، وأن محاولات القائمة لا تتكدس إلى الأبد.
إذا كنتم تبنون منتجات جديدة بسرعة، من المفيد تحويل هذه الافتراضات إلى قالب قابل لإعادة الاستخدام. للفرق التي تستخدم Koder.ai (koder.ai)، غالبًا ما يعني ذلك تعريف المهلات، إعدادات إعادة المحاولات، عدم التكرار، وقواعد القاطع مرة واحدة، ثم تطبيق نفس النمط عبر الخدمات أثناء التوليد والتكرار.