التعامل مع الوظائف المعلقة

مرحبا، أنا أشغل عدة عمال n8n يعالجون الوظائف من PostgreSQL. يقوم العمال بالمطالبة بالوظائف عن طريق تغيير حالتهم من قيد الانتظار إلى قيد المعالجة.
المشكلة هي أنه في بعض الأحيان يتعطل عامل أو يتم إعادة تشغيله بعد المطالبة بوظيفة. تبقى الوظيفة عالقة في المعالجة إلى الأبد ولا يتم التقاطها مرة أخرى.
أفكر في استخدام طابع زمني locked_at بحيث يمكن لعامل آخر تحديد الوظائف القديمة:
SELECT id, payload
FROM jobs
WHERE status = ‘processing’
AND locked_at < NOW() - INTERVAL ‘15 minutes’;
بعد ذلك يمكنني إعادة تعيين هذه الوظائف مرة أخرى إلى قيد الانتظار.
أنا مهتم بشكل أساسي بنمط يتعامل مع أعطال العمال بأمان دون إنشاء معالجة مكررة.

وصف المشكلة/الخطأ/السؤال

ما هي رسالة الخطأ (إن وجدت)؟

يرجى مشاركة سير العمل الخاص بك

(حدد العقد على لوحتك واستخدم اختصارات لوحة المفاتيح CMD+C/CTRL+C و CMD+V/CTRL+V لنسخ ولصق سير العمل.)

شارك الإخراج الذي أرجعته العقدة الأخيرة

معلومات عن إعداد n8n الخاص بك

  • إصدار n8n:
  • قاعدة البيانات (الافتراضي: SQLite):
  • إعداد n8n EXECUTIONS_PROCESS (الافتراضي: own, main):
  • تشغيل n8n عبر (Docker, npm, n8n cloud, تطبيق سطح المكتب):
  • نظام التشغيل:

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

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

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

المستندات:

المنتدى:

@Niffzy، @Emmas - لقد ساعدتما في مشاكل مشابهة من قبل، هل يمكنكما الاطلاع على هذا؟

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

@Mary_Berry

استخدم نموذج الإيجار/نبض القلب بدلاً من افتراض أن كل مهمة معالجة أكبر من 15 دقيقة قد انتهت.

سأعطي كل مهمة مطالب بها طابع زمني locked_at وويفضل أيضاً worker_id. يمكن للعمال تحديث نبض القلب بشكل دوري أثناء المعالجة.

للاسترجاع، سأستخدم تحديثاً ذرياً بحيث لا يمكن لعاملين استرجاع نفس المهمة:

UPDATE jobs
SET status = ‘pending’,
locked_at = NULL,
worker_id = NULL
WHERE id = $1
AND status = ‘processing’
AND locked_at < NOW() - INTERVAL ‘15 minutes’
RETURNING id;

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

للمهام طويلة الأجل، سأفضل بالتأكيد نبض القلب على المهلة الزمنية الثابتة:

مطالبة المهمة
↓
status = processing
↓
تحديث نبض القلب
↓
معالجة المهمة
↓
وضع علامة كمكتملة

ثم سيكون لدي سير عمل استرجاع صغير ينظر بشكل دوري عن المهام التي انتهت مهلة نبض قلبها.

مرحبا @Mary_Berry

اجعل ملكية المهمة صريحة بدلاً من الاعتماد فقط على مدى قدم حالة المعالجة.

عندما يختار عامل مهمة ما، امنحها معرّف عامل ووقت انتهاء صلاحية الإيجار:

UPDATE jobs
SET status = 'processing',
    worker_id = $1,
    lease_until = NOW() + INTERVAL '15 minutes'
WHERE id = $2
  AND status = 'pending'
RETURNING id;

أثناء تشغيل المهمة، يمكن للعامل تمديد صلاحيته:

UPDATE jobs
SET lease_until = NOW() + INTERVAL '15 minutes'
WHERE id = $1
  AND worker_id = $2
  AND status = 'processing';

يمكن لعملية الاسترجاع بعد ذلك البحث عن الإيجارات المنتهية الصلاحية وإعادة تلك المهام إلى الطابور.

مطالبة بمهمة
   ↓
الإيجار نشط
   ↓
معالجة + تجديد الإيجار
   ↓
اكتمال

إذا توقف العامل عن العمل، ستنتهي صلاحية الإيجار في النهاية ويمكن لعامل آخر أن يتولى المهمة.

سأجعل أيضاً معالجة المهمة الفعلية متكاملة بذاتها وأحتفظ بعداد إعادة محاولة، حتى تتمكن مهمة تفشل بشكل متكرر من الانتقال في النهاية إلى قائمة الرسائل غير القابلة للتسليم بدلاً من إعادة المحاولة إلى الأبد.

مرحباً @Mary_Berry
عقد الإيجار في جدولك لا يمكنه تجديد نفسه بالطريقة التي يفعلها n8n. يحتفظ n8n بعقد إيجار مدته 60 ثانية على التنفيذ ويرفعه كل 10 ثوانٍ على مؤقت، لكن التنفيذ عبارة عن تشغيل مباشر عبر العُقد بدون خيط خلفي، لذا لا شيء يلمس locked_at بينما عقدة HTTP Request محظورة. التجديد يحدث فقط حيث تعمل عقدة، مما يعني حلقة Loop Over Items مع عقدة تجديد بداخلها. أي شيء آخر يجب تحديد حجمه بدلاً من نبض القلب..

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

QUEUE_WORKER_LOCK_DURATION=900000

مع ترتيب معكوس، يسلم الحصاد الوظيفة إلى عامل ثان بينما الأول لا يزال يقوم بتشغيلها.