Bekleme döngümüz kendisi için 35 saat bekledi: SSH üzerinden pgrep -f ve pkill -f
Operasyonlar
31 Ekim'de SSH üzerinden küçük bir döngü başlattık: başka bir makinedeki bir çeviri işi bitene kadar bekle, ardından bir sonraki işi çalıştır. Çeviri işi o gece bitti. İki gün sonra tekrar baktığımızda, döngü 35 saattir bekliyordu ve sonraki iş hiç çalışmamıştı.
Döngü neydi
ssh build-host 'while pgrep -f "i18n_job.py example.com" >/dev/null; do sleep 30; done; ./follow-up.sh'
pgrep -f, her bir sürecin tam komut satırına karşı bir deseni eşleştirir. SSH, tırnak içindeki komutu bash -c 'while pgrep -f "i18n_job.py example.com" …' olarak çalıştırır ve bu komut satırı deseni içerir. pgrep kendi sürecini sonuçların dışında bırakır ancak onu başlatan kabuğu dışarıda bırakmaz. Dolayısıyla döngü hayatta kaldığı sürece bir eşleşme bulur: kendisi.
İkizi: pkill -f, içinde çalıştığı kabuğu öldürür
pkill -f ile aynı şey olur, sonuçları daha kötüdür:
ssh build-host 'pkill -f "worker.py --queue a"; nohup python3 worker.py --queue a &'
Kabuğun kendi komut satırı deseni içerdiğinden pkill kabuğu öldürür. İşçi durdurulur ve bir daha hiç başlatılmaz, SSH ise hata mesajı olmadan 255 koduyla çıkar. Bir tırnaklama sorunu gibi görünür, ilk seferde biz de öyle sanmıştık.
Eylül ile Ekim sonu arasında en az bir düzine kez bunlardan birine düştük: hiç gerçekleşmeyen yeniden başlatmalar, üç buçuk saat boyunca bir kontrolü tutan bir döngü, 50 dakika boyunca bir çeviri kuyruğunu tutan başka bir döngü ve bu.
Şimdi ne yapıyoruz
- Desende bir köşeli parantez:
pgrep -f "[i]18n_job.py example.com". Bir düzenli ifade olarak[i], i harfini eşleştirir, dolayısıyla iş hâlâ eşleşir; kabuğun komut satırı[i]karakterlerini içerir ve ifade bunları eşleştirmez. Yalnızca düz desen o satırda başka hiçbir yerde geçmiyorsa işe yarar: aynı satırda daha sonra gelen bir yeniden başlatma komutu tekrar eşleşir. - Bulmayı, durdurmayı ve başlatmayı ayrı SSH çağrılarıyla yapın. Bir çağrı
pgrep -afile süreçleri listeler, sonraki çağrı yazdırdığı PID'leri öldürür, üçüncü çağrı yeni süreci başlatır. - Bir desene değil, bir PID'e göre bekleyin:
tail --pid=1234 -f /dev/nullveyawhile kill -0 1234; do sleep 30; done. - Daha iyisi, işi systemd'e bırakın. Bir birim olarak çalıştırın ve
systemctl is-activekomutunu sorgulayın ya dasystemd-run --waitile başlatın. Yanlış yapılacak bir desen yok. - Her bekleme bir son tarihe sahip olmalı (
timeout 3h) ve ne zaman vazgeçtiğini belirtmeli. Son tarihi olmayan bir döngü sessizce başarısız olur.
Factory Floor, makinelerimizi çalıştıran Paket, systemd birimleri üzerinden çalışır: asla bir süreci komut satırına göre aramaz. Bizi zorlayan döngüler, elle yazdıklarımızdı.