Lorixen.

كيف تتعامل مع أحداث الأتمتة الفاشلة والمكررة

افترض أن أي حدث قد يفشل وأن أي حدث قد يصل مرتين. امنح كل حدث هوية ثابتة حتى يُتعرَّف على التكرار ويُتجاهل، وأعد المحاولة فقط في الإجراءات الآمنة التكرار، ونبّه شخصًا محددًا بالاسم عند حدوث فشل، ودوّن خطوة الاسترداد اليدوي بكلمات بسيطة. ثم اختبر مسارات الفشل عمدًا بدل انتظار فشل حقيقي.

لماذا يُعدّ التكرار والفشل أمرًا طبيعيًا

تنقطع الشبكات، وتنتهي مهلة الخدمات، ويعيد المرسلون المحاولة. وقد يبدو أن طلبًا قد فشل بينما نجح فعليًا، وإعادة المحاولة بشكل أعمى قد تُنشئ فاتورة ثانية أو حجزًا ثانيًا أو رسالة بريد ثانية. إن التصميم لهذا الاحتمال أمر معتاد وليس تشاؤمًا.

امنح كل حدث هوية ثابتة

فكرة مفتاح عدم التكرار أن يُرفق المرسل بالطلب مفتاحًا فريدًا، فيتمكن المستقبِل من التعرف على التكرار. تصف Stripe ذلك في واجهتها البرمجية: إذا حدث خطأ في الاتصال يمكنك إعادة الطلب دون خطر إنشاء كائن ثانٍ أو تنفيذ التحديث مرتين. تحفظ Stripe رمز الحالة ومحتوى الطلب الأول لكل مفتاح، وتُرجع النتيجة نفسها للطلبات اللاحقة التي تحمل ذلك المفتاح.

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

تفاصيل تستحق الاقتباس

توصي Stripe بمعرّفات عشوائية مثل UUID من الإصدار 4، وتنصح بعدم استخدام بيانات حساسة مثل عناوين البريد الإلكتروني كمفاتيح. وفي API v1 تذكر أنه يمكن حذف المفاتيح بعد 24 ساعة على الأقل، وأنها تقارن معاملات الطلب المكرر بالطلب الأصلي وتُرجع خطأ إذا اختلفت. وفي API v1 تشير أيضًا إلى أن جميع طلبات POST تقبل المفاتيح، وأنه لا ينبغي إرسال مفاتيح مع طلبات GET وDELETE لأنها بطبيعتها لا تتكرر أثرًا (idempotent). وفي API v1 تضيف أنه إذا فشل التحقق من المعاملات الواردة، أو تعارض الطلب مع طلب آخر قيد التنفيذ في الوقت نفسه، فلا تُحفظ نتيجة idempotent ويمكن إعادة الطلب. هذه تفاصيل خاصة بـ Stripe، لذا راجع وثائق الخدمة التي تستخدمها فعليًا.

عندما تصل نسختان في اللحظة نفسها

التكرارات المتزامنة هي الحالة التي يفوتها الفحص البسيط. تخيّل أن نسختين من حدث الحجز نفسه تصلان إلى سير عملك خلال ثانية واحدة. تبحث كل واحدة عن رقم الحجز في قائمة التأكيدات المرسلة، وتجده كل منهما غير موجود، وترسل كل منهما رسالة بريد. وعندما يكون الفحص والإرسال والتسجيل ثلاث خطوات منفصلة، توجد فجوة ترى فيها النسختان الحالة القديمة نفسها.

سُدّ الفجوة بالمطالبة بالحدث قبل التصرف. اجعل المطالبة خطوة واحدة لا تنجح إلا لنسخة واحدة، مثل إدراج صف يجب أن يكون رقم الحجز فيه فريدًا، أو تحديث مشروط يغيّر الحالة من جديد إلى قيد المعالجة فقط إذا كانت لا تزال جديدة. تمضي النسخة التي تفوز بالمطالبة، وتتوقف النسخة الخاسرة، أو تنتظر وتقرأ النتيجة المسجلة. امنح الحالة بضع قيم بسيطة، مثل تمت المطالبة وأُرسل وفشل ونتيجة غير معروفة، ليرى الشخص موضع كل حدث.

تصف AWS الفكرة نفسها من جهة الخدمة. ففي مقالة Amazon Builders' Library عن الواجهات البرمجية idempotent، يجب أن يحقق تسجيل رمز عدم التكرار وكل عملية تعديل تمت للطلب معًا خصائص العملية الذرية المتسقة المعزولة الدائمة (ACID)، بحيث لا تسجل الخدمة الرمز دون إنشاء المورد، ولا تنشئ المورد دون تسجيل الرمز. وينطبق ذلك على التغييرات داخل معاملة الخدمة نفسها. ولا يمتد إلى رسالة بريد تُرسل عبر مزوّد خارجي، إذ لا تستطيع أي معاملة قاعدة بيانات التراجع عنها أو تأكيدها. تعامل مع الأمرين كمشكلتين منفصلتين.

عندما يكون إرسال البريد نفسه غير مؤكد

تمنع المطالبة الذرية النسختين من المتابعة معًا. لكنها لا تخبرك بما إذا كانت الرسالة قد سُلّمت، ولا تضمن وحدها ألا يُرسل تكرار أبدًا. افترض أن نسخة فازت بالمطالبة واستدعت خدمة البريد وانتهت مهلة الاتصال. قد تكون الرسالة قد خرجت، وقد لا تكون، وقد تكون في قائمة الانتظار. إعادة المحاولة الأعمى تخاطر برسالة ثانية، وعدم فعل شيء يخاطر بألا تصل أي رسالة. تصف AWS المعضلة نفسها لطلب لا يتلقى ردًا: لا يعرف المستدعي ما إذا تم العمل، وقد يحتاج إلى خطوة مطابقة لمعرفة ذلك.

لذلك قبل استدعاء خدمة البريد، سجّل الحالة بشكل دائم على أنها محاولة إرسال، النتيجة غير معروفة، وتأكد من حفظ هذا السجل بحيث ينجو من أي انهيار. لا تغيّره إلى أُرسل أو فشل إلا بعد أن يعطي المزوّد إجابة واضحة. وإذا انهارت العملية بعد خروج الرسالة وقبل وسمها بأنها أُرسلت، يبقى الحدث غامضًا بشكل ظاهر ويذهب إلى المطابقة. ولا يُعاد إرساله تلقائيًا أبدًا. تعامل مع هذه الحالة على أنها تحتاج إلى شخص، وسمِّ من يطابقها، مثل المالك أو مدير المكتب. ينبغي أن تذكر ملاحظته أين يتحقق، مثل مجلد المرسل أو سجل التسليم في خدمة البريد، وهل تلقى العميل التأكيد. السجلات لا تحسم المسألة دائمًا: غياب إدخال لا يثبت أنه لم يُسلَّم شيء، ولذلك لا يجعل إعادة الإرسال آمنة. وإذا تعذر تحديد النتيجة بالتحقق، فاترك الحدث دون حسم لدى المسؤول المسمّى بدل إعادة الإرسال. وفقط بعد أن يحدد المسؤول النتيجة يضع علامة أُرسل على الحدث، أو يعيد الإرسال مرة واحدة ويسجل ذلك. وإذا كانت خدمة البريد لديك تقبل مفتاحًا خاصًا بها للإرسال فاستخدمه، لكن اقرأ وثائقها أولًا، لأن الدعم ومدة الاحتفاظ يختلفان بين الخدمات.

أعد المحاولة فقط في ما هو آمن

تصنيف الإجراءات في مجموعتين يسهّل القرار.

  • آمنة التكرار: قراءة البيانات، وضبط الحالة على قيمة ثابتة، وحفظ السجل نفسه تحت الهوية نفسها.
  • غير آمنة دون حماية: إرسال بريد إلكتروني، أو خصم مبلغ من بطاقة، أو إنشاء سجل جديد، أو الإضافة إلى مجموع جارٍ.
  • في الإجراءات غير الآمنة، طالِب بهوية الحدث في خطوة واحدة لا تفوز بها إلا نسخة واحدة، وتحقق من وجود نجاح سابق قبل التصرف. تقلل المطالبة من محاولات التكرار لكنها لا تثبت نجاح إجراء خارجي.
  • باعِد بين محاولات الإعادة وتوقف بعد عدد قليل منها، حتى لا تُثقل على خدمة معطلة.

اجعل الأخطاء مرئية

يتيح لك n8n تحديد سير عمل للأخطاء يعمل عند فشل أي تنفيذ، مثلًا لإرسال بريد أو تنبيه Slack. يبدأ سير عمل الأخطاء بعقدة Error Trigger، ويمكن لسير عمل أخطاء واحد أن يخدم عدة سير عمل. وتتيح عقدة Stop and Error إفشال تشغيل عمدًا وفق شروط تختارها. أيًّا كانت الأداة التي تستخدمها، احرص على أن يصل الفشل إلى شخص محدد بالاسم لا إلى سجل لا يقرؤه أحد.

اكتب خطوة الاسترداد

اكتب لكل نوع من الفشل جملة واحدة: ماذا يفعل الشخص بعد ذلك. من الأمثلة إعادة إرسال رسالة من السجل، أو وسم سجل بأنه عولج يدويًا، أو التواصل مع العميل. وضّح أين يُنظر ومن يقرر. ملاحظة الاسترداد التي توجد في رأس شخص واحد فقط تفشل في أول مرة يكون فيها في إجازة.

مثال افتراضي

تخيّل سير عمل يرسل بريد تأكيد عند حفظ حجز. نظام الحجز يستدعي سير العمل أحيانًا مرتين، وأحيانًا في اللحظة نفسها تقريبًا. يطالب سير العمل أولًا برقم الحجز في جدول تأكيدات يجب أن يكون كل رقم فيه فريدًا. فقط النسخة التي تفوز بالمطالبة تواصل الإرسال، ثم تضع على الحجز علامة أُرسل. وتتوقف النسخة الأخرى. وإذا كانت خدمة البريد متوقفة ورفضت الرسالة، ينبّه سير عمل الأخطاء المالك، فيتبع ملاحظة تقول بإعادة الإرسال من قائمة الحجوزات غير المؤكدة. وإذا انتهت مهلة الإرسال دون إجابة واضحة، يبقى الحجز موسومًا بنتيجة غير معروفة، ويراجع المالك سجل التسليم في خدمة البريد قبل إعادة الإرسال أو وسمه بأنه تم. هذا المثال افتراضي.

المصادر

اطّلع على أدلة أصحاب الأعمال

WhatsAppلنتحدث