Vente-sløyfen vår ventet i 35 timer på seg selv: pgrep -f og pkill -f over SSH
Drift
Den 31. oktober startet vi en liten sløyfe over SSH: vent til et oversettelsesjobb på en annen maskin er ferdig, og kjør deretter en oppfølgingsjobb. Oversettelsesjobben ble ferdig samme kveld. Da vi så etter to dager, hadde sløyfen ventet i 35 timer, og oppfølgingen hadde aldri kjørt.
Hva sløyfen var
ssh build-host 'while pgrep -f "i18n_job.py example.com" >/dev/null; do sleep 30; done; ./follow-up.sh'
pgrep -f matcher et mønster mot hele kommandolinjen til hver prosess. SSH kjører den anførte kommandoen som bash -c 'while pgrep -f "i18n_job.py example.com" …', og den kommandolinjen inneholder mønsteret. pgrep utelater sin egen prosess fra resultatene, men ikke skallet som startet den. Så lenge sløyfen levde, fant den en treff: seg selv.
Dens tvilling: pkill -f dreper skallet det kjører i
Det samme skjer med pkill -f, med verre resultater:
ssh build-host 'pkill -f "worker.py --queue a"; nohup python3 worker.py --queue a &'
Skallets egen kommandolinje inneholder mønsteret, så pkill dreper skallet. Arbeideren stoppes og startes aldri igjen, og SSH avsluttes med kode 255 uten feilmelding. Det ser ut som et anførselsproblem, noe vi trodde første gang.
Mellom september og slutten av oktober falt vi i den ene eller den andre minst en halv dusin ganger: omstarter som aldri skjedde, en sløyfe som holdt en sjekk i tre og en halv time, en annen som holdt en oversettelseskø i 50 minutter, og denne.
Hva vi gjør nå
- En klammeparentes i mønsteret:
pgrep -f "[i]18n_job.py example.com". Som et regulært uttrykk matcher[i]bokstaven i, så jobben matcher fortsatt; skallets kommandolinje inneholder tegnene[i], som uttrykket ikke matcher. Det hjelper bare hvis det vanlige mønsteret ikke finnes noe annet sted på den linjen: en omstartskommando senere på samme linje matcher igjen. - Finn, stopp og start i separate SSH-kall. Ett kall lister prosessene med
pgrep -af, det neste dreper PID-ene det skrev ut, et tredje starter den nye prosessen. - Vent på en PID, ikke et mønster:
tail --pid=1234 -f /dev/null, ellerwhile kill -0 1234; do sleep 30; done. - La systemd ta seg av jobben. Kjør den som en enhet og spør
systemctl is-active, eller start den medsystemd-run --wait. Det finnes ingen mønster å gjøre feil på. - Alle vent har en tidsfrist (
timeout 3h) og sier fra når den gir opp. En løkke uten tidsfrist feiler uten å varsle.
Factory Floor, kittet som kjører maskinene våre, fungerer via systemd-enheter: den leter aldri etter en prosess etter kommandolinjen. Det var de løkkene vi skrev for hånd, som bitt oss.