Ο βρόχος αναμονής μας περίμενε τον εαυτό του για 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 σκοτώνει το κέλυφος. Ο εργαζόμενος σταματά και δεν ξεκινά ξανά, και το 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 να αναλάβει τη δουλειά. Εκτελέστε το ως μονάδα και ρωτήστε με
systemctl is-active, ή ξεκινήστε το μεsystemd-run --wait. Δεν υπάρχει μοτίβο που να κάνετε λάθος. - Κάθε αναμονή έχει προθεσμία (
timeout 3h) και δηλώνει πότε εγκαταλείπει. Ένας βρόχος χωρίς προθεσμία αποτυγχάνει σιωπηλά.
Factory Floor, η εργαλειοθήκη που τρέχει τις μηχανές μας, λειτουργεί μέσω μονάδων systemd: δεν ψάχνει ποτέ μια διαδικασία από τη γραμμή εντολών της. Οι βρόχοι που μας έκαψαν ήταν αυτοί που πληκτρολογήσαμε με το χέρι.