كيف تكتشف سير العمل الذي يعمل بشكل جيد لكنه لا يفعل شيئاً؟
لقد كنت أقوم بتشغيل عمليات العملاء في n8n لفترة من الوقت وأستمر في الوقوع في نفس الفشل، وأنا فضولي كيف يتعامل الآخرون معه.
يتم تنفيذ سير العمل. كل عقدة خضراء. لا توجد أخطاء مرمية. وصفر سجلات هبطت فعلياً.
عادة ما يكون شيئاً هادئاً في المنطقة المصدرية: انتهت صلاحية الرمز، تم إعادة تسمية حقل، غيرت واجهة برمجة التطبيقات شكل استجابتها، أو فلتر يطابق فجأة لا شيء. سير عمل الخطأ لا يطلق أبداً، لأنه من وجهة نظر النظام لم يحدث شيء خاطئ.
الجزء الذي يكلفني ليس الإصلاح، بل التأخير. بحلول الوقت الذي يلاحظه أحد، كان معطوباً لعدة أيام.
لذا، خاصة بالنسبة لأولئك الذين يقومون بتشغيل سير العمل للعملاء:
• هل تتحقق من أي شيء بخلاف سير عمل الخطأ؟
• هل قام أحد بربط شيء خارجي لهذا (Healthchecks.io، ping cron، عقدة نبض مخصصة)؟
• هل تتحقق من عدد السجلات، أم فقط من اكتمال التشغيل؟
• أم بصراحة، هل تكتشفها عادة عندما يخبرك العميل؟
هذا الأخير هو ما أحاول منع حدوثه. مهتم بسماع ما يعمل فعلاً للناس.
نعم—التمييز المفيد هو بين صحة التنفيذ مقابل صحة النتيجة. عادةً ما أقسمها إلى ثلاث فحوصات:
صحة التشغيل: البداية/النهاية والمدة والمحاولات المتكررة وحالة المصدر ومسار خطأ التنفيذ.
صحة المخرجات: نافذة العدد المتوقع والحداثة والحقول المطلوبة وتجزئة المخطط والفحوصات ذات المفاتيح المكررة.
صحة الاستقبال: معرّف سجل المصب أو إقرار أو إدخال استثناء صريح.
تشغيل أخضر مع صفر غير متوقع يجب أن يخضع للمراجعة، وليس النجاح. احتفظ بدليل التشغيل الأولي، ونبّه على الفشل المتتالي حتى لا تنتج ضوضاء من نتيجة واحدة شرعية فارغة.
إنها بيانات مثبت مملوكة لـ RomeoApps، وليست تلمترية العميل، ولا تستخدم أي بيانات اعتماد. بالنسبة لسير عمل حقيقي، عادةً ما يكون التنفيذ المحررّ ونافذة المخرجات المتوقعة والإقرار بالوجهة كافيين لتحديد الفحص الأول المفقود.
تفصيل جيد أعلاه حول صحة التنفيذ مقابل الإخراج مقابل الإيصال. من الناحية العملية على جانب n8n، إليك نمط خفيف الوزن يلتقط هذا بدون بنية تحتية إضافية:
وحده Error Trigger لن يساعد هنا — فهو ينطلق فقط على الاستثناءات غير المعالجة، ومشكلتك هي بالضبط الحالة التي لا يرمي فيها شيء.
أنهِ سير عملك الرئيسي باستخدام IF node يفحص عدد العناصر الفعلي (أو حقل معين) الصادرة من آخر “عقدة حقيقية”. إذا كان 0 أو لا يطابق ما تتوقعه، وجهه إلى Stop and Error node — وهذا يجبر n8n على معاملة النتيجة الفارغة/الخاطئة كفشل، الأمر الذي يؤدي بعد ذلك إلى تفعيل سير عملك للأخطاء / الإخطار.
بالنسبة لمشكلة “الصمت لعدة أيام” تحديداً، فإن Schedule Trigger منفصل يعمل جيداً: كل N دقيقة/ساعة يتحقق (HTTP Request أو استعلام DB) مما إذا تم إنشاء السجل المتوقع بشكل مباشر في الأسفل مؤخراً، ويرسل لك تنبيهاً إذا لم يكن كذلك.
ضع فحص عدد السجلات في أقرب مكان ممكن من عقدة الكتابة الفعلية (مباشرة بعد كتابة Kintone/DB/API)، وليس في نهاية سير العمل — بهذه الطريقة تلتقطها قبل أن تستمر الفروع الأخرى في العمل على بيانات سيئة.
النمط الذي أنقذني أكثر: لا تدع “انتهى سير العمل بدون خطأ” يكون إشارة النجاح الوحيدة لديك — أضف دائماً عقدة تأكيد واحدة واضحة قبل السماح لسير العمل بالانتهاء بنجاح.
هذه مشكلة معروفة وجد مهمة. كما قال الآخرون، تحتاج إلى التمييز بين سير عمل يحتوي على خطأ وسير عمل يعمل بنجاح لكنه لا ينتج شيئاً. لا يمكنك الاعتماد فقط على سير العمل الخاص بالخطأ المدمج للحالة الثانية.
يمكنك إضافة فحص التأكيد في نهاية تدفقك، لكنني أفضل فحص “حارس البوابة” في البداية مباشرة. إنه أكثر كفاءة لأنه يوقف بقية سير عملك من الجري إذا لم تكن هناك بيانات للمعالجة.
النمط بسيط:
بعد استعلامك الرئيسي (على سبيل المثال، “الحصول على السجلات من قاعدة البيانات”، “طلب HTTP”)، أضف عقدة IF.
اضبط عقدة IF للتحقق مما إذا كان عدد العناصر الواردة مساوياً لـ 0.
المسار الصحيح هو الذي يؤدي إلى “الفشل”. هذا هو المكان الذي يمكنك فيه تعيين ما يجب فعله عند حدوث أشياء معينة (على سبيل المثال، إرسال رسالة Slack، إنشاء تذكرة Jira، إرسال بريد إلكتروني). يمكنك إضافة عقدة Stop و Error هنا لتفعيل سير عمل الخطأ العام.
الفرع الكاذب هو مسار “النجاح”، الذي يستمر إلى بقية منطق سير عملك الطبيعي.
بهذه الطريقة، يستمر سير العمل فقط إذا كان لديه بيانات، وتحصل على تنبيه فوري إذا لم يسحب أي شيء.
هذا ممتاز، خاصة الجزء الذي يتحدث عن وضع فحص العدد مباشرة بعد عقدة الكتابة وليس في النهاية. هذا خطأ أراه كثيراً حيث يتحقق الناس في وقت متأخر جداً وتنتشر البيانات السيئة بالفعل في المراحل اللاحقة
نهج سير العمل للنبض المنفصل هو في الأساس ما توصلت إليه أيضاً عند البناء حول هذا. لكن الجزء الذي يصبح معقداً في النطاق الكبير هو الحفاظ على أحد تلك الأسالیب لكل سير عمل العميل، عندما تصل إلى 15 أو 20 أتمتة عبر عملاء مختلفين، يبدأ الإعداد اليدوي للنبض باستهلاك الوقت الفعلي. هذا كان المحرك الرئيسي بالنسبة لي لبناء شيء يتعامل معه خارج سير العمل نفسه
بوابة الحارس في البداية ذكية، لم أكن أفكر بالأمر بهذه الطريقة. تمنع السلسلة بأكملها من التشغيل على بيانات فارغة بدلاً من تركها تمر والتحقق في النهاية. بالتأكيد أكثر كفاءة
شيء واحد أستمر في مواجهته مع هذا النمط، إنه يعمل بشكل رائع لكل سير عمل ولكنه لا يحل حالة “سير العمل توقف عن التشغيل تماماً”. مثل إذا كان مشغل الجدول نفسه يتوقف عن الإطلاق لأي سبب كان، فإن عقدة IF لا تحصل حتى على فرصة للتحقق. هذا هو السبب في أهمية طبقة نبضات القلب في الأعلى، شيء خارجي يلاحظ أن سير العمل ذهب صامتاً، ليس فقط أنه تشغيل فارغ
بخصوص جزء “سير العمل الواحد في كل عميل لا يتسع” — الشيء الذي أصلحه لي كان عكسه: بدلاً من أن يمتلك كل سير عمل مراقبه الخاص، اجعل كل سير عمل يبلغ عن نقطة تفتيش مشتركة واحدة، وقم بتشغيل مراقب واحد على تلك الجداول.
عملياً:
سير عمل فرعي صغير جداً، checkin، يُستدعى عبر Execute Workflow في نهاية كل خط أنابيب (والأفضل بعد عقدة الكتابة مباشرة، كما قال nathan3). يأخذ ثلاث قيم: pipeline (اسم مستقر)، count (العناصر المكتوبة بالفعل)، ok (منطقي). يُدرج صف واحد في جدول heartbeats: pipeline، last_seen، last_count، last_ok. ثلاثة حقول، عقدة واحدة لإضافتها لكل سير عمل، لا توجد مراقبة لكل عميل.
جدول expectations واحد تملأه يدوياً مرة واحدة لكل خط أنابيب: pipeline، max_silence_minutes، min_count. هذا هو الجزء الذي يستحق القيام به بوعي — كتابة “يجب أن يعمل هذا على الأقل كل ساعة وينتج سجل واحد على الأقل” هو ما يحول المراقبة من انطباعات إلى فحص حقيقي.
سير عمل Schedule Trigger واحد، كل 15 دقيقة، يربط بين الاثنين: أرسل تنبيهاً إذا now - last_seen > max_silence_minutes (يقبض على حالة “المشغل توقف عن الإطلاق بالكامل” التي ذكرتها، لأن غياب تحديث الصف بحد ذاته هو الإشارة)، أو last_count < min_count، أو last_ok = false. إضافة العميل #21 هي صف واحد في expectations بالإضافة إلى عقدة Execute Workflow واحدة، وليس سير عمل نبضات جديد.
شيئان أنقذاني من الألم مع هذا:
أرسل تنبيهاً عند N فشل متتالي، وليس الأول، لأي شيء يحتوي على نوافذ فارغة بشكل شرعي. وإلا فإن فترة الهدوء في نهاية الأسبوع ستدرب الجميع على تجاهل القناة.
اجعل المراقب نفسه ينبض في مكان خارجي (خدمة cron ping جيدة). كل شيء أعلاه يعيش داخل n8n، لذا إذا كانت الحالة معطلة، فالمراقب معطل أيضاً وتحصل على صمت بدلاً من تنبيه. هذا اعتماد خارجي واحد ويغطي الأسطول بالكامل بدلاً من واحد لكل سير عمل.
بخصوص “هل لا يزال الجدول الزمني يطلق النار” على وجه التحديد: إذا كنت تستضيف ذاتياً، يمكنك أيضاً قراءة هذا مباشرة من واجهة برمجة التطبيقات REST الخاصة بـ n8n — GET /api/v1/executions?workflowId=...&limit=1 وقارن startedAt مقابل الإيقاع المتوقع. نفس سير عمل المراقب، لا توجد أجهزة قياس في سير العمل المراقب على الإطلاق، على الرغم من أنك تفقد إشارة “تشغيل بدون كتابة”، لذا سأستخدمه جنباً إلى جنب مع صفوف تسجيل الوصول بدلاً من استبدالها.
القيمة Count == 0 تلتقط النسخة الصاخبة من هذا. لكن النسخة التي آذتنا أكثر هي count > 0 لكنها خاطئة: تهبط N صف، ويمر التأكيد، وكل واحد منها يحتوي على قيمة فارغة في الحقل الذي كان مهماً لأن حقلاً في المصدر الأعلى تمت إعادة تسميته ولا تزال عقدة الكتابة الخاصة بك تقبل الصف. لا شيء في نمط IF-node-on-count في هذا الخيط يلتقط ذلك، لأنه يتحقق من العدد الكلي وليس الشكل.
الحل هو نفس شكل العقدة، فقط يؤكد شيئاً مختلفاً: بعد الكتابة، تحقق من أن الحقلين أو الثلاثة حقول التي تعتمد عليها فعلاً ليست فارغة والنوع تقريباً صحيح، وليس أن عدد العناصر غير صفر. تكلفة شرط واحد إضافي على نفس عقدة IF التي وصفها nathan3 بالفعل، وهو يلتقط نمط الفشل حيث تؤدي إعادة التسمية أو تغيير عقد واجهة برمجية التطبيق إلى تدهور البيانات بدلاً من مسحها، وهي الطريقة الأكثر شيوعاً التي يؤدي بها تغيير المخطط إلى كسر شيء ما في تجربتي.
شيء واحد آخر يستحق البناء إذا كنت تفرض الفواتير على هذه الأشغال على الإطلاق: قم بتوجيه نفس التأكيد إلى كل ما يقرر “هل عمل هذا العد،” وليس فحص ثانٍ وأكثر تساهلاً. من السهل أن ينتهي الحال بحالة حيث تنبهك النسخة الصارمة ولكن بوابة منفصلة وأقدم هي التي لا تزال تحدد ما إذا كان العميل سيُفرض عليه دفع مقابل الأشغال، وهذان الاثنان ينجرفان بصمت بعيداً عن بعضهما البعض بمرور الوقت.
النقطة التي يؤكد عليها themineworks هي التي كنت سأركز عليها: العدد هو العدد الأساسي، وليس الصحة، والفشل الذي يكلفك فعلاً هو وصول N صف حيث الحقل الذي تعتمد عليه يكون فارغاً (null)، أو ما هو أسوأ، موجود وبدو معقول لكنه خاطئ. يتم إعادة تسمية حقل ما في المصدر الأعلى، لكن عقدة الكتابة الخاصة بك تقبل الصف بشكل طبيعي، والآن لديك بيانات تبدو حقيقية لكنها خاطئة بصمت. التأكيدات null والنوع تمسك النسخة التي تتدهور إلى فارغة. لكنها لا تمسك النسخة التي تتدهور إلى شيء معقول، غير فارغ، من النوع الصحيح، وببساطة خاطئ، لأنه لا شيء في الصف يبدو خاطئاً. الفحص الوحيد الذي يمسك ذلك هو شمعة الإجابة المعروفة. جنباً إلى جنب مع حركة المرور الحقيقية، ادفع حفنة من المدخلات الاصطناعية التي كتبت إجابتها الصحيحة مقدماً، وشغّلها عبر خط أنابيب البث الحي من البداية إلى النهاية على جدول زمني، وأكد أن الإخراج يساوي الإجابة المعروفة، وليس فقط أنه مشكل بشكل صحيح. إذا بدأت خريطة ما تشير بصمت إلى الحقل الخاطئ لكن الصحيح، فإن القيمة المتوقعة للشمعة تتوقف عن المطابقة وتحصل على فشل عالي الصوت في نفس اليوم، لأنك تقارن مقابل الحقيقة وليس مقابل المعقولية. كما أنها تغلق الفجوة التي أثارها Cam. شمعة لا تتمكن من الإبلاغ هي نفسها التنبيه، لذا فإن نفس الآلية تمسك كل من خط الأنابيب الذي يصبح صامتاً والقيم التي تصبح خاطئة بدقة، مع وجود فحص خارجي واحد يراقب نتيجة الشمعة بدلاً من نبض واحد لكل سير عمل. في الواقع العملي، أقوم بتشغيل ثلاث طبقات: العدد والتأكيدات null أو النوع مباشرة بعد الكتابة للفشل العالي الصوت، والعلامات المائية للحجم للنزيف البطيء، وشمعة إجابة معروفة مجدولة للحالة المعقولة لكن الخاطئة التي لا تستطيع الطبقتان الأولى رؤيتها هيكلياً.
حالة count > 0 لكن wrong-shape هي التي أقلق بشأنها أيضاً.
نمط مفيد هو جعل فحص “النجاح” النهائي يثبت وجود الأثر الذي تهتم به، وليس فقط أن شيئاً ما تم كتابته. على سبيل المثال: معرّف المصب موجود، الحقول التجارية المطلوبة غير فارغة، معرّف المصدر محفوظ، ومعرّف التشغيل مرفق في مكان ما يمكنك التدقيق فيه لاحقاً.
وإلا ستنتهي بتنفيذ أخضر ووجهة مكتظة بالسجلات لا يمكن لأحد استخدامها فعلياً.
@rodri.galloswork ذكرت أن الحفاظ على نبضات القلب لكل سير عمل يبدأ في استهلاك الوقت الفعلي عند 15-20 أتمتة عبر العملاء، وأنه يدفعك لبناء شيء خارج سير العمل. هذا شيء كنت أنظر إليه أيضًا..(أنا مطور، أتعلم قبل أن أقرر ما إذا كان يجب أن أبني).
وجدت شيئًا في 2.36.7 كنت أفترض أنه يعمل بطريقة مختلفة.
عندما تتوقف شروط IF عن المطابقة، لا يتم وضع علامة تخطي على العقدة في تلك الفرع. إنها غير موجودة في runData على الإطلاق. التنفيذ لا يزال يعيد status: success.
لذلك إذا كنت تكرر العقد بحثًا عن حالة سيئة، فلن تجد شيئًا. الإشارة هي مفتاح غير موجود.
إعادة الإنتاج: schedule trigger، code node ينبعث منه صفوف، IF التي لا يمكن أبدًا أن تطابق، code node على الفرع الصحيح. تلك العقدة الأخيرة مفقودة ببساطة.
كل شيء في هذا الخيط يخبرك متى حدث خطأ في التشغيل. هناك خطوة قبل ذلك لم يذكرها أحد، وهي موجهة خصيصاً لمشكلة تشغيل 15-20 تلقائياً: يمكنك معرفة أي من مسارات العمل لديك حتى قادرة على هذا الفشل من خلال قراءة JSON مسار العمل، قبل أن تقوم بأي أدوات قياس.
أنماط التأكيد أعلاه صحيحة. لكن كل واحدة منها تكلف عقدة وحكماً في كل مسار عمل، وعند 20 مسار عمل عبر عملاء مختلفين، هذا بالضبط الجزء الذي يستهلك الوقت. إذاً السؤال المفيد يصبح: أي منها يحصل على التأكيد أولاً؟
هذا يمكن الإجابة عليه من الملف. لكل عقدة تكتب شيئاً خارج n8n — قاعدة بيانات، Sheets، CRM، Slack، أي HTTP POST/PUT/DELETE — تحقق مما إذا كان هناك مسار من المشغّل إلى نهاية مسار العمل يصل إلى النهاية دون المرور عبر تلك العقدة. IF بدون شيء على الفرع الخاطئ، Switch بدون fallback، filter يمكن أن يفرغ قائمة العناصر: كل واحد يعطيك تشغيلاً ينتهي بشكل طبيعي ولا يكتب شيئاً. هذه مسارات العمل هي حيث عقدة check-in من CameronDWills و assertion من nathan3 تستحق استثمارها. مسارات العمل حيث كل عملية كتابة على كل مسار يمكن أن تنتظر.
باليد هذا يستغرق بضع دقائق لكل واحد: اسرد عمليات الكتابة، ارجع بالتتبع إلى المشغّل، اسأل ما إذا كان هذا التشغيل سيبدو ناجحاً.
قمت بتشغيل هذا الفحص عبر 2,043 قالب n8n عام. 13.5% كان لديها على الأقل حالة واحدة عالية الخطورة — عملية كتابة يمكن تخطيها بينما التقرير لا يزال يظهر النجاح. الأنماط منسقة ومصقولة، لذا كنت أقرأ ذلك كحد أدنى وليس كمتوسط.
سؤال واحد بالعودة، بما أنك الشخص الذي يعيش هذا: عندما يصبح مسار عمل العميل هادئاً، هل التأخير في الغالب عدم معرفة أن شيئاً ما انقطع، أو عدم معرفة أي من العشرين تفتح أولاً؟ كنت أفترض الثاني وأود أن أعرف إذا كنت مخطئاً.
إفصاح: قمت بإنشاء صفحة مجانية تقوم بهذا الفحص — الصق JSON مسار العمل وستسرد عمليات الكتابة التي يمكن تخطيها. بدون تسجيل دخول، محلل في متصفحك بحيث لا يغادر JSON الصفحة: https://stillrunning.dev. يسعدني شرح مسار عمل هنا بدلاً من ذلك إذا كنت تفضل عدم لصقه في أي مكان.
قم بتعيين سير عمل للأخطاء → هذا هو الملاذ الأخير المطلق في حالة فشل كل شيء آخر، ويجب أن يفعل ما يلي:
سجل الخطأ
أخطر الأشخاص أو نفسك فقط
(اختياري لكن مفيد جداً) إذا كان سير عمل webhook، يمكنك ببساطة إلحاق الحمولة (payload) بقاعدة بيانات الأخطاء الخاصة بك مع زر لإعادة إرسالها إلى webhook؛ هذا يوفر عليك الوقت اللازم للذهاب إلى التنفيذات وفتح سير العمل وما إلى ذلك.. فهو يعيد تشغيل سير العمل من هناك، بشرط أن يكون لديك مفاتيح idempotency، وأنه فشل عابر.
استخدم مفتاح idempotency جيد
خطأ على مستوى سير العمل
قم بإعداد نظام التحقق من صحة الحمولة (payload)؛ يجب أن يحل معظم مشاكلك المتعلقة بالبيانات الفارغة.
قم بتعيين التحقق الأولي من الحمولة
قم بتعيين التحقق النهائي من الحمولة، قبل عملية الكتابة
لا تستخدم الفلاتر أبداً؛ بدلاً من ذلك، استخدم عقد IF مع التحقق الصارم من الشروط، وعقدة إيقاف وعقدة مسار الخطأ لكل شيء لا يتوافق مع هذه الشروط
هذا سيسمح لك بضمان بروتوكول صارم جداً من البداية؛ سيتم طرح كل شيء كخطأ لا ينطبق علىهذه الشروط. يمكنك بعد ذلك أن تكون استباقياً مع العملية، وتوسع الشروط مع مرور الوقت.
أخطاء على مستوى العقدة
تعطيل المتابعة عند الفشل
استخدم إعادة المحاولة عند الفشل
في بعض الحالات المحددة جداً (على الرغم من أنها نادرة جداً)، استخدم مسار الخطأ.
التحقق من صحة على مستوى الحقل
معالجة البيانات عند وصولها، تحويل أو تنظيف حسب البيانات التي تصل
استخدم قيمة احتياطية حيث لزم الأمر: null وundefined وغيرها
عادة ما يكون لدي قاعدة بيانات مراقبة مع حالة يتم تعيينها؛ يمكنك أن يكون لديك ذلك كجزء من البيانات التي تعالجها (تؤدي عملية سير العمل، والعملاء المحتملين لديهم بالفعل حالة)
أو يمكنك تعيينه يدوياً، خاصة إذا كنت تحاول أن تكون استباقياً بينما تصلح هذه الأخطاء بشكل دائم عند وصولها بإلحاق التشغيل بحالة البدء بعد التحقق الأول من الحمولة وتحديث الحالة بعد حالة التحقق الأخير. (هذا بوضوح مبالغ فيه بنسبة 99% من جميع حالات الاستخدام في رأيي)
هناك بعض الأشياء المفيدة الأخرى التي يجب فعلها، لكن بصراحة هذا يغطي معظمها.
الشيء الرئيسي هو استخدام بروتوكول منهجي.
ملخص
فرض قواعد صارمة على كل مستوى
كل شيء ليس ما تريده
تأكد من حصولك على إشعار وأنك تستطيع التحقيق بسرعة
إذا لم تكن خطأ بل حالة جديدة من البيانات للمعالجة، فقم بزيادة الشروط
الإصدار المقلوب من @CameronDWills له الشكل الصحيح. الشيء الوحيد الذي أود إضافته يتعلق بالجدول الذي يعتمد عليه.
كل نمط في هذا الخيط — عقد تسجيل الدخول والتأكيدات والكناريوهات الاختبارية — يحتاج إلى تعاون سير العمل. تضيف عقدة أو تكتب توقعاً. هذا جيد عندما تبني الشيء بنفسك. إنها مشكلة في الحالتين اللتين تسبب الألم فعلاً: سير العمل الذي ورثته، والحالات العميلة حيث لا تكون حراً في تعديل 20 خط أنابيب قبل أن تعرف أيها مهم.
هناك إشارة يمكنك الحصول عليها من الخارج دون لمس أي شيء. نقطة التنفيذ تعطيك، لكل سير عمل، متى بدأ كل تشغيل وكيف انتهى. شيئان ينبثقان من هذا السجل:
الإيقاع. رتب تنفيذات سير العمل وخذ الفجوة الوسيطة. هذا هو التوقع — أنت لا تكتب بخط يدك max_silence_minutes لكل خط أنابيب، وهو عند 20 سير عمل عبر العملاء نفس مشكلة التوسع في معطف جديد. سير عمل يعمل بالساعة لمدة شهر ولم يعمل لمدة ستة أشهر هي حالة “توقف المشغل عن الحريق” التي أثارها @Cam، يتم اكتشافها دون عقدة نبض.
معدل الخطأ مقابل خطه الأساسي الخاص به، وليس عتبة ثابتة. سير عمل فشل دائماً بنسبة 2٪ ليس خبراً. واحد ارتفع من 2٪ إلى 30٪ هو. العتبات الثابتة عبر أسير عمل متنوعة هي، في تجربتي، السبب في أن الناس يكتمون هذه التنبيهات بحلول الشهر الثاني.
لا يحل محل التأكيدات. لا يمكن للواجهة أن تخبرك أن التشغيل كتب قيماً فارغة — فقط أنه عمل وما أرجعه. الرؤية من الخارج تخبرك أن سير العمل صمت أو أصيب بالمرض؛ الرؤية من الداخل تخبرك أنه كذب. تريد الاثنين، لكن واحد فقط يعمل على سير عمل لم تفتحه بعد.
(تحذير: انتهاء الصلاحية الدقيقة لا تُكشف بواسطة الواجهة، لذا تمسك رمز 401 المنتهي الصلاحية بعد انتهائه، وليس قبله.)
هناك تمييز مدفون في هذا الخيط أعتقد أنه يستحق الفصل، لأن الإصلاحات مختلفة.
كل شيء تقريباً أعلاه يتعلق بسير عمل كان يعمل في السابق ثم توقف بصمت — انتهت صلاحية رمز، تمت إعادة تسمية حقل، تغيرت شكل الاستجابة. تأكيدات العدد وسير عمل نبض القلب هي الإجابة الصحيحة على ذلك.
النصف الآخر من هذه المشكلة هو سير عمل لم يعمل أبداً على الإطلاق، وأبلغ عن النجاح من التشغيل الأول جداً.
قمت مؤخراً بتنفيذ خمسة من سير عملي الخاص بشكل صحيح للمرة الأولى — مقابل خادم محلي يقف مكان واجهات برمجة التطبيقات، وتسجيل كل نص طلب صادر. كانت جميع الخمسة معيبة، وكانت جميعها خضراء:
عقدة HTTP Request (typeVersion 4.2, contentType json) مع الحمل الموجود في معامل body بدلاً من jsonBody. تقرأ تلك العقدة jsonBody، لذا فإن ما غادر الجهاز فعلياً كان {"":""}. أجابت نقطة النهاية برقم 200. كل عقدة خضراء.
نص موجه مخزن في عقدة Set بدون = في البداية، لذا لم تقم n8n بتقييمه. تلقت النموذج الأحرف الحرفية {{ $json.article_text }} وأجابت على أي حال، مما أنتج استجابة معقولة تماماً تم إنشاؤها من لا شيء.
خطوة تحليل نشرت استجابة واجهة برمجة تطبيقات على العنصر الذي كانت تثريه، مما أدى إلى الكتابة فوق الحقول الأصلية. كل شيء في اتجاه مجرى النهر يعمل بسعادة على الكائن الخاطئ.
لا شيء من هذه يرمي. فحص عدد العنصرات لا يقبضها أيضاً، لأن الأعداد صحيحة جميعها — عنصر واحد في، عنصر واحد خارج، في كل خطوة. ما هو خاطئ هو محتوى ما تم إرساله، ولا شيء في عرض التنفيذ يُظهر ذلك إلا إذا فتحت العقدة وقرأتها.
الشيء الوحيد الذي قبضها كان توجيه كل تكامل إلى خادم محلي يسجل نص الطلب، وتشغيل سير العمل مرة واحدة، وقراءة السجل. عشرون دقيقة للإعداد، وقد وجدت شيئاً في كل سير عمل وجهته إليه منذ ذلك الحين.
إذن إلى جانب “هل العدد هو ما أتوقعه”، سأضيف سؤالاً ثانياً: “هل نظرت فعلاً إلى ما يرسله هذا؟” لأي شيء بالفعل في الإنتاج، الفراغات التي وصفها الناس أعلاه هي الإجابة. لأي شيء جديد، اقرأ البايتات مرة واحدة قبل أن تثق به.
منشور @enzosoftware هو ما كنت سأبني عليه، لأن “هل نظرت فعلاً إلى ما يرسله هذا؟” هو السؤال الصحيح، وتوجيه عملية تكامل نحو خادم محلي يسجل نص الطلب هو أرخص طريقة للإجابة عليه. نفس التجربة هنا، لم تعود نظيفة قط.
هناك سؤال بعد ذاك، وأنا لا أعتقد أنه ظهر بعد في الخيط: بمجرد أن تجد العطل وتكتب إصلاحاً، كيف تعرف أن الإصلاح يعمل؟
الإجابة الافتراضية هي نشر ومراقبة. وهذا يجعل الإنتاج منصة اختبار، لفئة خلل لا تعلن عن نفسها بحكم التعريف، لذلك “لا تنبيهات منذ الثلاثاء” لا يمكن تمييزه عن “لا يزال معطلاً، لا يزال صامتاً”. الإيقاع وخطوط الأساس لمعدل الخطأ التي وصفها Miguel_Ruilope ستكشفها في النهاية، لكن النهاية تحمل الكثير من الوزن هناك.
ما جعل هذا قابلاً للتطبيق بالنسبة لي كان الاحتفاظ بالتنفيذ المسجل من عندما انقطع، أجسام الطلب والاستجابة الفعلية بدلاً من ملخص، وإعادة تشغيل إصلاح مرشح مقابل هذا التسجيل الدقيق مع حظر الخروج. خاصيتان تؤديان العمل.
الشبكة المختومة: إذا كان بإمكان إعادة التشغيل الوصول إلى واجهة برمجة التطبيقات المباشرة، فأنت تختبر واجهة برمجة التطبيقات اليوم، وليس تلك التي كسرتك، والنتيجة الخضراء لا تعني شيئاً.
البايتات الخام بدلاً من ملخص: فئة الفشل كاملة هنا هي الشكل، ومثال نص JSON الفارغ أعلاه هو بالضبط ما تتخلص منه سجل مختصر.
ثم السؤال ضيق بما يكفي للإجابة عليه فعلاً: هل يحول هذا الإصلاح هذا الفشل المسجل المحدد إلى الناتج الصحيح، نعم أم لا. أسهل بكثير أن تكون متأكداً منه أكثر من “هل سير العمل هذا سليم”.
الحد الصريح منه هو أن هذا يعمل فقط للأخطاء التي سجلتها بالفعل. بالنسبة لأي شيء لم يتم التقاطه بعد، القراءة الثابتة من @ali.alsamraay لمخطط سير العمل JSON، وقراءة البايتات مرة واحدة قبل الثقة بسير عمل جديد، أفضل بشكل صارم، لأن أياً منهما لا يحتاج إلى أن يكون الفشل قد حدث أولاً. من الخارج للداخل، من الداخل للخارج وإعادة التشغيل يجيبان على ثلاثة أسئلة مختلفة، وأنا لا أعتقد أن أياً منها يحل محل الآخرين.
الكشف، بنفس روح ali: بنيت أداة تقوم بجزء إعادة التشغيل والتحقق، وقاعدة التصميم الرئيسية لها هي أنها ترفض الادعاء بأن إصلاح يعمل عندما لا تستطيع إثباته. إنها مجانية وليس لديها مستخدمون حتى الآن، لذلك يرجى التعامل معها كنهج يستحق السرقة بدلاً من التوصية. فكرة الإعادة المختومة تستحق أكثر من تطبيقي لها.
التسجيل المختوم مع حجب الخروج هو الشكل الصحيح، وقاعدة البايتات الخام هي الجزء الذي أود أن أؤكد عليه. سجل موجز لحالة الجسم الفارغ يبدو متطابقًا مع حالة صحية، لذلك إذا تجاهل التسجيل ذلك، فإن إعادة التشغيل لا تثبت شيئًا.
هناك نصف أود أن أضيفه، ويقع فقط بعد النقطة التي يتحول فيها تسجيلك إلى اللون الأخضر.
أصلحت تسعة عيوب عبر خمسة سير عمل، وأعدت تشغيل كل واحد منها مقابل خادم السجل المحلي، وقارنت الأجسام المسجلة مع ما كنت أتوقعه. عادت جميعها صحيحة. الإصلاح كان حقيقيًا.
كان أحد تلك سير العمل معروضًا للبيع كملف قابل للتنزيل. أي شخص اشتراه كان سيحصل على الإصدار المعطل، لأن الشيء الذي تحققت منه والشيء الذي تم تسليمه قد انجرفا بصمت عن بعضهما البعض. لقد اكتشفت ذلك فقط بتنزيل منتجي بالطريقة التي يفعلها العميل والتحقق من البايتات مقابل الملف الذي قمت ببنائه. لم تطابق.
لذلك أجابت إعادة التشغيل “هل يحول هذا الإصلاح هذا الفشل المسجل إلى المخرجات الصحيحة”. لم تستطع الإجابة عن “هل الإصلاح موجود في القطعة التي يتلقاها أي شخص فعلاً”. بالنسبة لسير عمل تقوم بتشغيله بنفسك، هذان السؤال واحد. بمجرد أن يكون هناك تصدير أو خطوة نشر أو استيراد قالب أو ملف يقوم شخص ما بتنزيله، ينفصلان، والفجوة هادئة بالطريقة التي كانت عليها الحشرة الأصلية.
الفحص الذي يغلقها ممل. جلب القطعة بالطريقة التي يحصل عليها المستقبل، وليس بالطريقة التي قمت ببنائها، وأعد التشغيل من تلك. إذا كان ملفًا، قم بحساب بصمته. إذا كان استيرادًا، قم باستيراده إلى مثيل نظيف وقم بتشغيل إعادة التشغيل المختومة مقابل أي شيء يخرج من الجانب الآخر.
فئة الفشل التي تصفها هي أن اللون الأخضر لا يعني العمل. هذه هي نفس الفئة خطوة واحدة أبعد. الإصلاح لا يعني الشحن.
جدول التوقعات الخاص بـ CameronDWills هو الجزء الذي كان يمكنني البناء عليه، لأن كتابة “يجب أن يعمل هذا مرة واحدة على الأقل كل ساعة وينزل سجل واحد على الأقل” هو ما يحول المراقبة من مجرد شعور إلى فحص حقيقي. وهو أيضاً الجزء الذي يتدهور، وأنا لا أعتقد أن المناقشة غطت ما يحدث له في الشهر الثاني.
ذهاب min_count إلى حالة قديمة مع تغير الحجم هو النصف المعروف، والاقتراحات المتعلقة بالوسيط المتحرك أعلاه تتعامل معه. النصف الذي عضني هو ما يحدث بمجرد أن تتجاوز العدادات وتبدأ بالتأكيد على أن قيماً محددة يجب أن تظهر. تلك القائمة تصبح كائن صيانة، ولا أحد يحافظ عليها.
مشغل يقوم بسحب كشف حسابات بنكية أخبرني كيف انتهى الحال به. قامت إحدى قيمه المسماة بإعادة تسمية نفسها في الخادم الأعلى. الفحص شكا كل صباح وتوقف عن قراءته. كان لا يزال يعمل وكان لا يزال صحيحاً. لقد أصبح ببساطة ضوضاء، وهو أسوأ من لا شيء، لأن سير العمل كان الآن غير مراقب وهو اعتقد أنه كان مراقباً.
ما أصلحه هو رفض التعامل مع “القيمة المتوقعة مفقودة” كحالة واحدة. إنها ثلاث حالات، وتريد مخرجات مختلفة.
لم يُرَ في أي من التشغيلات الأخيرة: تمت إعادة تسمية أو إيقاف. ليست إنذاراً، بل تعليمات. قم بتحديث القائمة، وقل بوضوح أنه سيتكرر حتى يقوم شخص ما به.
يُرى في عدد قليل من التشغيلات: حقيقي، لكن ليس لكل تشغيل. سطر شهري في سحب كل ساعة. لم ينتمِ أبداً إلى قائمة كل تشغيل، والتنبيه عليه يعني التنبيه على كل تشغيل تقريباً.
يُرى باستمرار والآن اختفى: الإنذار الفعلي، والإنذار الوحيد من بين الثلاثة يستحق الاستيقاظ من أجله.
ذو صلة، وينطبق على نافذة المراقب أيضاً: يجب أن يكون الفحص قادراً على الامتناع عن الإجابة. ثلاثون تنفيذاً لسير عمل كل ساعة هو ثلاثون ساعة من الأدلة. اسأل تلك البيانات عما إذا وصلت فاتورة ربع سنوية والمخرجات الصادقة هي “غير مغطاة”، وليس “لا”. يقصر EXECUTIONS_DATA_MAX_AGE تلك النافذة بهدوء، والتشغيل المحذوف ليس دليلاً على الغياب، بل ليس دليلاً على أي شيء.
المنشور أعلاه يضعه كما يلي: الإصلاح لا يعني الشحن. هذا نفس الشكل في اتجاه مختلف: التشغيل لا يعني القراءة.