Naša zanka za čakanje je čakala 35 ur sama nase: pgrep -f in pkill -f prek SSH
Operacije
31. oktobra smo začeli majhno zanko prek SSH: počakaj, da se prevajalniški posel na drugi napravi konča, nato zaženi nadaljnji posel. Prevajalniški posel se je končal tisto noč. Ko smo znova pogledali dva dni pozneje, je zanka čakala 35 ur, nadaljnji posel pa se nikoli ni zagnal.
Kaj je bila zanka
ssh build-host 'while pgrep -f "i18n_job.py example.com" >/dev/null; do sleep 30; done; ./follow-up.sh'
pgrep -f ujame vzorec glede na celotno ukazno vrstico vsakega procesa. SSH zažene navedeni ukaz kot bash -c 'while pgrep -f "i18n_job.py example.com" …', ta ukazna vrstica pa vsebuje vzorec. pgrep iz rezultatov izpusti svoj lastni proces, ne pa lupine, ki ga je zagnala. Torej, dokler je bila zanka živa, je našla ujemanje: sama sebe.
Njen dvojček: pkill -f ubije lupino, v kateri teče
Enako se zgodi s pkill -f, s slabšimi posledicami:
ssh build-host 'pkill -f "worker.py --queue a"; nohup python3 worker.py --queue a &'
Lastna ukazna vrstica lupine vsebuje vzorec, zato pkill ubije lupino. Delavec je ustavljen in nikoli več ne zažene, SSH pa se konča s kodo 255 brez sporočila o napaki. Videti je kot težava z narekovaji, kar smo prvič tudi mislili.
Med septembrom in koncem oktobra smo vsaj enajstkrat naleteli na eno ali drugo težavo: ponovni zagoni, ki se nikoli niso zgodili, zanka, ki je tri in pol ure držala preverjanje, druga, ki je 50 minut držala prevajalniško vrsto, in ta.
Kaj zdaj počnemo
- Oklepaj v vzorcu:
pgrep -f "[i]18n_job.py example.com". Kot regularni izraz[i]ujame črko i, zato se posel še vedno ujame; ukazna vrstica lupine vsebuje znake[i], ki jih izraz ne ujame. To pomaga le, če se preprost vzorec nikoli drugje na tej vrstici ne pojavi: ukaz za ponovni zagon kasneje na isti vrstici se znova ujame. - Poiščite, ustavite in zaženite v ločenih klicih SSH. Prvi klic našteje procese z
pgrep -af, naslednji ubije izpisane PID-e, tretji zažene nov proces. - Čakajte na PID, ne na vzorec:
tail --pid=1234 -f /dev/nullaliwhile kill -0 1234; do sleep 30; done. - Še bolje, naj sistem systemd prevzame opravilo. Zaženite ga kot enoto in povprašajte s
systemctl is-activeali ga zaženite ssystemd-run --wait. Tu ni vzorca, ki bi ga lahko napačno uporabili. - Vsak čakanje ima rok (
timeout 3h) in pove, kdaj odneha. Zanka brez roka tiho odpove.
Factory Floor, komplet, ki poganja naše stroje, deluje prek enot systemd: nikoli ne išče procesa po njegovi ukazni vrstici. Zanke, ki so nas ujele, so bile tiste, ki smo jih napisali ročno.