@Niffzy لديه الشكل الصحيح والمفتاح الحتمي هو الجزء المهم. هناك شيئان أود إضافتهما، لأن هناك سباقًا متبقيًا في هذا التدفق، وأحدهما يحدد ما إذا كنت تحتاج إلى فحص الحالة على الإطلاق.
سباق الفحص-ثم-العمل
في هذا التسلسل:
فحص حالة واجهة برمجية خارجية → المعالجة فقط إذا لزم الأمر
إذا وصلت محاولتا إعادة محاولة قريبة من بعضهما، يمكن لكليهما أن تمرا فحص الحالة قبل أن تعالج إحداهما، ثم تعالج كلاهما. الفهرس الفريد يوقف صفًا ثانيًا، لكنه لا يوقف استدعاء واجهة برمجية ثانيًا. عند إعادة محاولة انتهاء الجلسة، تكون المحاولتان عادة بفاصل قليل من الثواني فقط، وهو بالضبط النافذة الزمنية.
ما يغلقها هو المطالبة بالعمل بشكل ذري، مع عقد إيجار بحيث لا يتمكن الانهيار من إيقاف الحدث إلى الأبد:
INSERT INTO processed_events (event_id, status, claimed_at, attempts)
VALUES ($1, 'processing', now(), 1)
ON CONFLICT (event_id) DO UPDATE
SET claimed_at = now(),
attempts = processed_events.attempts + 1
WHERE processed_events.status = 'processing'
AND processed_events.claimed_at < now() - interval '5 minutes'
RETURNING *;
الحصول على صف يعني أنك تمتلك العمل. عدم الحصول على أي شيء يعني أنه إما انتهى بالفعل أو يعمل عليه شخص آخر، وتتوقف. إنها جملة واحدة، لذا فهي ذرية، ولا يمكن لمحاولتي إعادة محاولة متزامنتين أن تفوز بالمطالبة معًا.
عقد الإيجار يصحح أيضًا شيئًا في النسخة الأصلية. علامة ON CONFLICT DO NOTHING عادية تضع الصف في حالة ‘processing’ ولم يتم إطلاقه مطلقًا، لذا فإن الانهيار الدقيق الذي تسأل عنه يترك هذا الصف في حالة ‘processing’ إلى الأبد. تصل إعادة المحاولة إلى التضارب وتفعل شيئًا، والحدث يُسقط بصمت. هذا عادة أسوأ من النسخة المكررة، لأنه لا شيء ينبهك. اضبط الفاصل الزمني براحة أطول من أسوأ زمن استجابة واجهة برمجية واقعي لديك.
قد لا تحتاج إلى فحص الحالة على الإطلاق
إذا كانت واجهة برمجية خارجية تقبل رأس Idempotency-Key، أرسل مفتاحك الحتمي وتخطّ فحص الحالة بالكامل. جانبهم يقوم بإزالة التكرارات وينقل لك النتيجة الأصلية، وهي ذرية من جانبهم بطريقة لا يمكن لفحص من جانبك أن يكون، وتكلفها لا شيء على المسار السعيد بدلاً من رحلة ذهاب وإياب إضافية على كل حدث. يستحق قراءة المستندات الخاصة بهم قبل بناء الخطوة الإضافية. احتفظ بفحص الحالة كخطة بديلة للواجهات البرمجية التي لا تدعمها.
شيئان بخصوص جانب n8n
أوقف retryOnFail على عقدة واجهة برمجية. إعادة محاولة على مستوى العقدة تعيد التشغيل داخل نفس التنفيذ وستتجاوز بسعادة المنطق الذي لفته حول العقدة.
من الجدير أيضًا تأكيد أي إعادة محاولة تراها بالفعل، لأن الاثنين يبدوان متطابقين في البيانات ولهما إصلاحات مختلفة. افتح قائمة التنفيذ الخاصة بك. إذا كانت النسخ المكررة عبارة عن تنفيذات منفصلة بفاصل قليل من الثواني مع حمولات متطابقة، فهذا هو المتصل الذي يعيد المحاولة، والإصلاح هو أن تستجيب عقدة Webhook على الفور وتقوم بالعمل البطيء بعد ذلك، بحيث لا يمكن لانتهاء الجلسة أن يبدأ تشغيلًا ثانيًا. إذا كان تنفيذًا واحدًا يكتب مرتين، فهذه إعادة محاولة على مستوى العقدة. يستحق استبعاد أولاً، لأنه إذا تبين أنه المتصل فإن جميع آلية الحالة تعالج عرضًا.
شيء واحد أخير
حتى مع كل ما سبق، فإن التسليم مرة واحدة على الأقل بالإضافة إلى الأعطال يعني أن بعض الصفوف ستنتهي بها الحال متوقفة في منتصف الرحلة. سير عمل مجدول صغير يلتقط أي شيء لا يزال في حالة ‘processing’ بعد عقد الإيجار والتوفيق معه ضد واجهة برمجية يغلق الحلقة. بدونه، هذه هي الحلقات التي لا تسمع عنها أبدًا.