انتظرت حلقة الانتظار لدينا 35 ساعة لنفسها: pgrep -f و pkill -f عبر SSH
العمليات
في 31 أكتوبر بدأنا حلقة صغيرة عبر SSH: انتظر حتى تنتهي مهمة ترجمة على جهاز آخر، ثم شغّل مهمة تابعة. انتهت مهمة الترجمة تلك الليلة. عندما نظرنا مرة أخرى بعد يومين، كانت الحلقة تنتظر منذ 35 ساعة، ولم تُشغَّل المهمة التابعة أبدًا.
ما كانت عليه الحلقة
ssh build-host 'while pgrep -f "i18n_job.py example.com" >/dev/null; do sleep 30; done; ./follow-up.sh'
تطابق pgrep -f نمطًا مع سطر الأوامر الكامل لكل عملية. يشغّل SSH الأمر المقتبس كـ bash -c 'while pgrep -f "i18n_job.py example.com" …'، ويحتوي سطر الأوامر هذا على النمط. تستثني pgrep عمليتها الخاصة من النتائج، لكنها لا تستثني الصدفة التي بدأتها. لذا، طالما كانت الحلقة نشطة، كانت تجد تطابقًا: نفسها.
نظيرتها: pkill -f تقتل الصدفة التي تعمل فيها
يحدث الشيء نفسه مع pkill -f، بنتائج أسوأ:
ssh build-host 'pkill -f "worker.py --queue a"; nohup python3 worker.py --queue a &'
يحتوي سطر الأوامر الخاص بالصدفة نفسها على النمط، لذا تقتل pkill الصدفة. يتوقف العامل ولا يُشغَّل مرة أخرى أبدًا، ويخرج SSH برمز 255 دون رسالة خطأ. يبدو الأمر وكأنه مشكلة اقتباس، وهو ما اعتقدناه في المرة الأولى.
بين سبتمبر ونهاية أكتوبر، وقعنا في أحدهما أو الآخر ما لا يقل عن اثنتي عشرة مرة: عمليات إعادة تشغيل لم تحدث أبدًا، وحلقة احتجزت فحصًا لمدة ثلاث ساعات ونصف، وأخرى احتجزت قائمة انتظار الترجمة لمدة 50 دقيقة، وهذه الحلقة.
ما نفعله الآن
- أقواس مربعة في النمط:
pgrep -f "[i]18n_job.py example.com". كتعبير منتظم، يطابق[i]الحرف i، لذا لا يزال العمل يطابق؛ يحتوي سطر أوامر الصدفة على الأحرف[i]، والتي لا يطابقها التعبير. لا يساعد هذا إلا إذا لم يظهر النمط العادي في أي مكان آخر على ذلك السطر: فإن أمر إعادة تشغيل لاحق في نفس السطر يطابق مرة أخرى. - اعثر، أوقف، وشغّل في استدعاءات SSH منفصلة. استدعاء واحد يسرد العمليات باستخدام
pgrep -af، التالي يقتل معرفات العمليات (PIDs) التي طبعتها، والثالث يشغّل العملية الجديدة. - انتظر على PID، وليس على نمط:
tail --pid=1234 -f /dev/null، أوwhile kill -0 1234; do sleep 30; done. - والأفضل من ذلك، دع systemd يتولى المهمة. شغّله كوحدة (unit) واستعلم باستخدام
systemctl is-active، أو ابدأه باستخدامsystemd-run --wait. لا يوجد نمط يمكن أن تخطئ فيه. - كل انتظار له مهلة نهائية (
timeout 3h) ويحدد متى يتوقف. الحلقة (loop) التي لا مهلة لها تفشل بصمت.
Factory Floor، الحزمة التي تشغّل أجهزتنا، تعمل عبر وحدات systemd: فهي لا تبحث أبدًا عن عملية عبر سطر أوامرها. الحلقات التي سببت لنا مشاكل كانت تلك التي كتبناها يدويًا.