Saya memiliki skrip python yang akan memeriksa antrian dan melakukan tindakan pada setiap item:
# checkqueue.py
while True:
check_queue()
do_something()
Bagaimana cara menulis skrip bash yang akan memeriksa apakah skrip tersebut berjalan, dan jika tidak, mulai saja. Kira-kira kode pseudo berikut (atau mungkin harus melakukan sesuatu seperti ps | grep
?):
# keepalivescript.sh
if processidfile exists:
if processid is running:
exit, all ok
run checkqueue.py
write processid to processidfile
Saya akan menyebutnya dari crontab:
# crontab
*/5 * * * * /path/to/keepalivescript.sh
Jawaban:
Hindari PID-file, crons, atau apa pun yang mencoba untuk mengevaluasi proses yang bukan anak-anak mereka.
Ada alasan yang sangat bagus mengapa di UNIX, Anda HANYA dapat menunggu anak-anak Anda. Metode apa pun (ps parsing, pgrep, menyimpan PID, ...) yang mencoba untuk mengatasi yang cacat dan memiliki lubang menganga di dalamnya. Katakan saja tidak .
Alih-alih, Anda membutuhkan proses yang memantau proses Anda untuk menjadi induk proses. Apa artinya ini? Ini berarti hanya proses yang memulai proses Anda yang dapat menunggu hingga berakhir. Dalam bash, ini benar-benar sepele.
Sepotong kode bash di atas berjalan
myserver
dalam satuuntil
lingkaran. Baris pertama dimulaimyserver
dan menunggu sampai akhir. Ketika itu berakhir,until
periksa status keluarnya. Jika status keluar adalah0
, itu berarti berakhir dengan anggun (yang berarti Anda memintanya untuk ditutup, dan berhasil). Dalam hal ini kami tidak ingin memulai kembali (kami hanya meminta untuk mematikan!). Jika status keluar tidak0
,until
akan menjalankan loop body, yang memancarkan pesan kesalahan pada STDERR dan me-restart loop (kembali ke baris 1) setelah 1 detik .Mengapa kita menunggu sebentar? Karena jika ada sesuatu yang salah dengan urutan startup
myserver
dan crash segera, Anda akan memiliki loop yang sangat intensif untuk memulai dan crash terus-menerus di tangan Anda. Yangsleep 1
menghilangkan ketegangan dari itu.Sekarang yang perlu Anda lakukan adalah memulai skrip bash ini (secara tidak serempak, mungkin), dan itu akan memonitor
myserver
dan memulai kembali sesuai kebutuhan. Jika Anda ingin memulai monitor saat boot (membuat server "hidup" reboot), Anda dapat menjadwalkannya di cron pengguna Anda (1) dengan sebuah@reboot
aturan. Buka aturan cron Anda dengancrontab
:Kemudian tambahkan aturan untuk memulai skrip monitor Anda:
Kalau tidak; lihat inittab (5) dan / etc / inittab. Anda dapat menambahkan baris di sana untuk
myserver
memulai pada level init tertentu dan direspawn secara otomatis.Edit.
Biarkan saya menambahkan beberapa informasi tentang mengapa tidak menggunakan file PID. Meskipun mereka sangat populer; mereka juga sangat cacat dan tidak ada alasan mengapa Anda tidak hanya melakukannya dengan cara yang benar.
Pertimbangkan ini:
Daur ulang PID (membunuh proses yang salah):
/etc/init.d/foo start
: mulaifoo
, tulisfoo
PID ke/var/run/foo.pid
foo
entah bagaimana mati.bar
) membutuhkan PID acak, bayangkan ia mengambilfoo
PID lama.foo
hilang:/etc/init.d/foo/restart
membaca/var/run/foo.pid
, memeriksa untuk melihat apakah masih hidup, menemukanbar
, berpikir itufoo
, membunuhnya, memulai yang barufoo
.File PID menjadi basi. Anda perlu logika yang terlalu rumit (atau harus saya katakan, non-sepele) untuk memeriksa apakah file PID sudah basi, dan logika seperti itu lagi rentan
1.
.Bagaimana jika Anda bahkan tidak memiliki akses tulis atau berada dalam lingkungan baca-saja?
Komplikasi yang tidak ada gunanya; lihat betapa sederhananya contoh saya di atas. Tidak perlu mempersulit itu sama sekali.
Lihat juga: Apakah file-PID masih cacat saat melakukannya 'benar'?
Ngomong-ngomong; bahkan lebih buruk dari file PID yang diuraikan
ps
! Jangan pernah melakukan ini.ps
sangat tidak bisa diport. Meskipun Anda menemukannya di hampir setiap sistem UNIX; argumennya sangat bervariasi jika Anda menginginkan keluaran non-standar. Dan output standar HANYA untuk konsumsi manusia, bukan untuk penguraian scripted!ps
mengarah ke BANYAK positif palsu. Ambilps aux | grep PID
contoh, dan sekarang bayangkan seseorang memulai proses dengan nomor di suatu tempat sebagai argumen yang sama dengan PID yang Anda lihat dengan dasmon Anda! Bayangkan dua orang memulai sesi X dan Anda mengambil X untuk membunuh X Anda. Itu semua jenis yang buruk.Jika Anda tidak ingin mengelola sendiri prosesnya; ada beberapa sistem yang sangat baik di luar sana yang akan bertindak sebagai monitor untuk proses Anda. Lihat ke runit , misalnya.
sumber
while true; do myprocess; done
tetapi perhatikan bahwa sekarang tidak ada cara untuk menghentikan proses.trap 'kill $(jobs -p)' EXIT; until myserver & wait; do sleep 1; done
Lihatlah monit ( http://mmonit.com/monit/ ). Ini menangani mulai, berhenti dan mulai ulang skrip Anda dan dapat melakukan pemeriksaan kesehatan plus restart jika perlu.
Atau lakukan skrip sederhana:
sumber
Cara termudah untuk melakukannya adalah menggunakan kawanan pada file. Dalam skrip Python Anda akan melakukannya
Dalam shell Anda benar-benar dapat menguji apakah itu berjalan:
Tetapi tentu saja Anda tidak perlu menguji, karena jika sudah berjalan dan Anda me-restart, itu akan keluar bersama
'other instance already running'
Ketika proses mati, semua deskriptor file ditutup dan semua kunci secara otomatis dihapus.
sumber
flock
... pada kenyataannya, halaman manual secara eksplisit menunjukkan caranya!exec {lock_fd}>/tmp/script.lock; flock -x "$lock_fd"
adalah bash setara dengan Python Anda, dan meninggalkan kunci ditahan (jadi jika Anda kemudian menjalankan suatu proses, kunci akan tetap ditahan sampai proses itu keluar).flock
adalah cara yang benar, tetapi skrip Anda salah. Satu-satunya perintah yang perlu Anda atur di crontab adalah:flock -n /tmp/script.lock -c '/path/to/my/script.py'
Anda harus menggunakan monit, alat unix standar yang dapat memantau berbagai hal pada sistem dan bereaksi sesuai itu.
Dari dokumen: http://mmonit.com/monit/documentation/monit.html#pid_testing
Anda juga dapat mengonfigurasi monit untuk mengirimi Anda email saat melakukan restart.
sumber
sumber
ps ax|grep ...
. Anda hanya dapat menginstalnya atau menulis fungsi untuk itu: function psgrep () {ps ax | grep -v grep | grep -q "$ 1"}Saya tidak yakin seberapa portabelnya di seluruh sistem operasi, tetapi Anda mungkin memeriksa apakah sistem Anda berisi perintah 'run-one', yaitu "man run-one". Secara khusus, serangkaian perintah ini termasuk 'run-one-constant', yang tampaknya tepat seperti yang dibutuhkan.
Dari halaman manual:
Catatan: jelas ini dapat dipanggil dari dalam skrip Anda, tetapi juga menghilangkan kebutuhan untuk memiliki skrip sama sekali.
sumber
Saya telah menggunakan skrip berikut dengan sukses besar di banyak server:
catatan:
$INSTALLATION
mengandung cukup banyak jalur proses yang sama sekali tidak ambiguScript ini sebenarnya digunakan untuk mematikan instance tomcat yang sedang berjalan, yang ingin saya matikan (dan tunggu) di baris perintah, jadi meluncurkannya sebagai proses anak bukanlah pilihan bagi saya.
sumber
grep | awk
masih merupakan antipattern - Anda inginawk "/$INSTALLATION/ { print \$1 }"
mengubah yang tidak bergunagrep
menjadi skrip Awk, yang dapat menemukan baris dengan ekspresi reguler itu sendiri dengan sangat baik, terima kasih banyak.Saya menggunakan ini untuk Proses npm saya
sumber