GNU/Linux >> Belajar Linux >  >> Linux

Penguncian yang Benar Dalam Skrip Shell?

Terkadang Anda harus memastikan bahwa hanya satu contoh skrip shell yang berjalan pada waktu yang sama.

Misalnya tugas cron yang dijalankan melalui crond yang tidak menyediakan
penguncian sendiri (misalnya crond Solaris default).

Pola umum untuk menerapkan penguncian adalah kode seperti ini:

#!/bin/sh
LOCK=/var/tmp/mylock
if [ -f $LOCK ]; then            # 'test' -> race begin
  echo Job is already running!
  exit 6
fi
touch $LOCK                      # 'set'  -> race end
# do some work
rm $LOCK

Tentu saja, kode tersebut memiliki kondisi balapan. Ada jendela waktu di mana
eksekusi dua instance dapat maju setelah baris 3 sebelum salah satu dapat
menyentuh $LOCK berkas.

Untuk tugas cron ini biasanya tidak menjadi masalah karena Anda memiliki interval
menit antara dua pemanggilan.

Tetapi hal-hal bisa salah – misalnya ketika lockfile berada di server NFS –
yang hang. Dalam hal ini beberapa pekerjaan cron dapat memblokir pada baris 3 dan mengantri. Jika
server NFS aktif kembali maka Anda memiliki banyak pekerjaan paralel
yang sedang berjalan.

Mencari di web saya menemukan alat lockrun yang sepertinya merupakan solusi
yang baik untuk masalah itu. Dengannya Anda menjalankan skrip yang perlu dikunci seperti
ini:

$ lockrun --lockfile=/var/tmp/mylock myscript.sh

Anda dapat memasukkan ini ke dalam pembungkus atau menggunakannya dari crontab Anda.

Ini menggunakan lockf() (POSIX) jika tersedia dan kembali ke flock() (BSD). Dan lockf() dukungan atas NFS harus relatif luas.

Apakah ada alternatif untuk lockrun ?

Bagaimana dengan daemon cron lainnya? Apakah ada crond umum yang mendukung penguncian dengan
yang waras? Sekilas melihat halaman manual Vixie Crond (default pada
sistem Debian/Ubuntu) tidak menunjukkan apa pun tentang penguncian.

Apakah sebaiknya menyertakan alat seperti lockrun menjadi coreutils?

Menurut pendapat saya ini mengimplementasikan tema yang sangat mirip dengan timeout , nice dan teman-teman.

Jawaban yang Diterima:

Berikut cara lain untuk melakukan penguncian pada skrip shell yang dapat mencegah kondisi balapan yang Anda jelaskan di atas, di mana dua pekerjaan dapat melewati garis 3. noclobber opsi akan berfungsi di ksh dan bash. Jangan gunakan set noclobber karena Anda seharusnya tidak membuat skrip di csh/tcsh.

lockfile=/var/tmp/mylock

if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then

        trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT

        # do stuff here

        # clean up after yourself, and release your trap
        rm -f "$lockfile"
        trap - INT TERM EXIT
else
        echo "Lock Exists: $lockfile owned by $(cat $lockfile)"
fi

YMMV dengan penguncian pada NFS (Anda tahu, ketika server NFS tidak dapat dijangkau), tetapi secara umum jauh lebih kuat daripada sebelumnya. (10 tahun yang lalu)

Jika Anda memiliki tugas cron yang melakukan hal yang sama pada saat yang sama, dari beberapa server, tetapi Anda hanya perlu 1 instance untuk benar-benar dijalankan, hal seperti ini mungkin cocok untuk Anda.

Terkait:Perintah Toggle Shell Bluetooth MacOS sederhana?

Saya tidak memiliki pengalaman dengan lockrun, tetapi memiliki lingkungan kunci yang telah ditentukan sebelumnya sebelum skrip benar-benar berjalan mungkin membantu. Atau mungkin tidak. Anda baru saja mengatur tes untuk lockfile di luar skrip Anda dalam pembungkus, dan secara teoritis, tidak bisakah Anda mencapai kondisi balapan yang sama jika dua pekerjaan dipanggil oleh lockrun pada waktu yang sama persis, seperti halnya dengan 'di dalam- solusi skrip?

Penguncian file cukup banyak menghormati perilaku sistem, dan skrip apa pun yang tidak memeriksa keberadaan file kunci sebelum dijalankan akan melakukan apa pun yang akan mereka lakukan. Hanya dengan melakukan tes lockfile, dan perilaku yang tepat, Anda akan memecahkan 99% potensi masalah, jika tidak 100%.

Jika Anda sering mengalami kondisi balapan lockfile, ini mungkin merupakan indikator masalah yang lebih besar, seperti pekerjaan Anda tidak tepat waktu, atau mungkin jika interval tidak sepenting penyelesaian pekerjaan, mungkin pekerjaan Anda lebih cocok untuk di-daemon. .

EDIT DI BAWAH – 06-05-2016 (jika Anda menggunakan KSH88)

Berdasarkan komentar @Clint Pachl di bawah ini, jika Anda menggunakan ksh88, gunakan mkdir bukannya noclobber . Ini sebagian besar mengurangi kondisi balapan potensial, tetapi tidak sepenuhnya membatasinya (meskipun risikonya sangat kecil). Untuk informasi lebih lanjut, baca tautan yang diposting Clint di bawah.

lockdir=/var/tmp/mylock
pidfile=/var/tmp/mylock/pid

if ( mkdir ${lockdir} ) 2> /dev/null; then
        echo $$ > $pidfile
        trap 'rm -rf "$lockdir"; exit $?' INT TERM EXIT
        # do stuff here

        # clean up after yourself, and release your trap
        rm -rf "$lockdir"
        trap - INT TERM EXIT
else
        echo "Lock Exists: $lockdir owned by $(cat $pidfile)"
fi

Dan, sebagai keuntungan tambahan, jika Anda perlu membuat file tmp di skrip Anda, Anda dapat menggunakan lockdir direktori untuk mereka, mengetahui bahwa mereka akan dibersihkan ketika skrip keluar.

Untuk bash yang lebih modern, metode noclobber di atas harus sesuai.


Linux
  1. Izinkan Setuid Pada Skrip Shell?

  2. Array Asosiatif Dalam Skrip Shell?

  3. Bagaimana Cara Menjatuhkan Hak Istimewa Root Dalam Skrip Shell?

  1. Jalankan Skrip Shell Melalui Situs Web?

  2. Ekstensi File Untuk Skrip Unix Shell?

  3. Berbagi Variabel di Beberapa Skrip Shell?

  1. Bagaimana Menguji Kepatuhan Posix Dari Skrip Shell?

  2. Memisahkan Perintah Panjang Dalam Skrip Shell?

  3. Cara menjalankan skrip Python dari shell