Naše smyčka čekala 35 hodin sama na sebe: pgrep -f a pkill -f přes SSH
Provoz
31. října jsme spustili malou smyčku přes SSH: počkat, než na jiném stroji dokončí překladovou úlohu, a pak spustit navazující úlohu. Překladová úloha dokončila téhož večera. Když jsme se podívali znovu o dva dny později, smyčka čekala 35 hodin a navazující úloha se nikdy nespustila.
Co ta smyčka dělala
ssh build-host 'while pgrep -f "i18n_job.py example.com" >/dev/null; do sleep 30; done; ./follow-up.sh'
pgrep -f porovnává vzor s celým příkazovým řádkem každého procesu. SSH spustí uvozený příkaz jako bash -c 'while pgrep -f "i18n_job.py example.com" …' a tento příkazový řádek obsahuje vzor. pgrep vynechá svůj vlastní proces z výsledků, ale ne shell, který ho spustil. Takže dokud byla smyčka naživu, našla shodu: sama sebe.
Její dvojče: pkill -f zabije shell, ve kterém běží
Se pkill -f se děje totéž, s horšími následky:
ssh build-host 'pkill -f "worker.py --queue a"; nohup python3 worker.py --queue a &'
Příkazový řádek shellu obsahuje vzor, takže pkill zabije shell. Worker se zastaví a nikdy se znovu nespustí a SSH skončí s kódem 255 bez chybové hlášky. Vypadá to jako problém s uvozovkami, což jsme si zpočátku mysleli.
Mezi zářím a koncem října jsme do jednoho z nich nebo do druhého upadli nejméně tucetkrát: restarty, které se nikdy nestaly, smyčka, která držela kontrolu tři a půl hodiny, další, která držela frontu překladů 50 minut, a právě tato.
Co děláme teď
- Hranatá závorka ve vzoru:
pgrep -f "[i]18n_job.py example.com". Jako regulární výraz[i]odpovídá písmenu i, takže úloha stále odpovídá; příkazový řádek shellu obsahuje znaky[i], kterým výraz neodpovídá. Pomůže to jen tehdy, pokud se prostý vzor nikde jinde na řádku nevyskytuje: příkaz pro restart později na stejném řádku odpoví znovu. - Najít, zastavit a spustit v samostatných SSH voláních. Jedno volání vypíše procesy pomocí
pgrep -af, další zabije PID, které vypsal, třetí spustí nový proces. - Čekat na PID, ne na vzor:
tail --pid=1234 -f /dev/null, nebowhile kill -0 1234; do sleep 30; done. - Ještě lépe: nechte úlohu spravovat systemd. Spusťte ji jako unitu a dotazujte se pomocí
systemctl is-active, nebo ji spusťte příkazemsystemd-run --wait. Neexistuje žádný vzor, který byste mohli pokazit. - Každé čekání má termín (
timeout 3h) a říká, kdy to vzdá. Smyčka bez termínu selže potichu.
Factory Floor, balíček, který u nás pohání stroje, pracuje prostřednictvím systemd unit: nikdy nehledá proces podle příkazového řádku. Přesně ty smyčky, které nás zradily, jsme psali ručně.