ลูปรอของเราเองรอไป 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 จึงฆ่าเชลล์ ตัว worker ถูกหยุดและไม่เคยเริ่มใหม่ และ SSH ออกจากด้วยโค้ด 255 โดยไม่มีข้อความแสดงข้อผิดพลาด มันดูเหมือนปัญหาการครอบด้วยเครื่องหมายคำพูด ซึ่งเราเข้าใจเช่นนั้นในครั้งแรก
ระหว่างเดือนกันยายนถึงสิ้นเดือนตุลาคม เราตกอยู่ในสถานการณ์ใดสถานการณ์หนึ่งอย่างน้อยสิบสองครั้ง: การรีสตาร์ทที่ไม่เคยเกิดขึ้น ลูปที่ถือการตรวจสอบไว้สามชั่วโมงครึ่ง อีกตัวที่ถือคิวแปลไว้ 50 นาที และตัวนี้
สิ่งที่เราทำตอนนี้
- วงเล็บในแพทเทิร์น:
pgrep -f "[i]18n_job.py example.com"ในฐานะนิพจน์ปกติ[i]จับคู่ตัวอักษร i ดังนั้นงานยังคงจับคู่ได้ บรรทัดคำสั่งของเชลล์ประกอบด้วยอักขระ[i]ซึ่งนิพจน์ไม่จับคู่ มันจะช่วยได้ก็ต่อเมื่อแพทเทิร์นธรรมดาไม่ปรากฏที่อื่นในบรรทัดนั้น: คำสั่งรีสตาร์ทในภายหลังในบรรทัดเดียวกันจะจับคู่อีกครั้ง - ค้นหา หยุด และเริ่มในคำสั่ง SSH แยกกัน หนึ่งคำสั่งจะแสดงรายการกระบวนการด้วย
pgrep -afคำสั่งถัดไปจะฆ่า PID ที่พิมพ์ออกมา และคำสั่งที่สามจะเริ่มกระบวนการใหม่ - รอที่ 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) และระบุชัดเจนว่าจะยอมแพ้เมื่อใด ลูปที่ไม่มีกำหนดเวลาจะล้มเหลวเงียบ ๆ
Factory Floor ชุดเครื่องมือที่รันเครื่องจักรของเรา ทำงานผ่าน systemd units: มันไม่เคยค้นหาโปรเซสจาก command line ลูปที่เคยทำให้เราเจ็บปวดคือลูปที่เราพิมพ์ด้วยมือเอง