Oke, sederhananya saya memiliki skrip shell yang perlu menunggu sesuatu terjadi, tetapi ia memiliki file kunci dan beberapa proses anak yang perlu saya pastikan dirapikan jika skrip terputus.
Saya telah mencapai ini tanpa masalah dengan menggunakan trap
perintah untuk mengatur beberapa tindakan yang sesuai, dan telah menghasilkan skrip yang terlihat seperti ini:
#!/bin/sh
LOG="$0.log"
# Create a lock-file to prevent simultaneous access
lockfile -l 86400 "$LOG.lock" || $(echo 'Locking failed' >&2 && exit 3)
# Create trap for interrupt and cleanup
on_complete() {
echo $(date +%R)' Ended.' >> "$LOG"
kill $(jobs -p)
rm -f "$LOG.lock"
exit
}
trap 'on_complete 2> /dev/null' SIGTERM SIGINT SIGHUP EXIT
# Do nothing
echo $(date +%R)' Running…' >> "$LOG"
sleep 86400 &
while wait; do sleep 86400 &; done
Ini dapat dijalankan dengan baik di terminal melalui sh Example.sh
, dan mengakhiri dengan Ctrl + C
, menyebabkannya untuk menghapus file kunci tanpa keributan.
Saya kemudian mencoba membuat launchd
pekerjaan untuk skrip ini seperti:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.example</string>
<key>ProgramArguments</key>
<array>
<string>sh</string>
<string>~/Downloads/Example.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>EnableGlobbing</key>
<true/>
</dict>
</plist>
Membuat Example.sh dan Example.plist dari ~/Downloads
folder di atas memungkinkan saya untuk menjalankan launchd
pekerjaan melalui launchd load ~/Downloads/Example.plist
dan mengakhirinya melalui launchd unload ~/Downloads/Example.plist
. Namun, mengakhiri pekerjaan tidak menyebabkan a SIGTERM
mencapai skrip, yang malah SIGKILL
akan terjadi setelah batas waktu 20 detik.
Jadi yang ingin saya ketahui adalah; mengapa skrip saya tidak terima SIGTERM
, dan bagaimana saya bisa memastikannya?
sumber
Jawaban:
Masalah utama di sini adalah bahwa Bash biasanya tidak membunuh anak-anak non-bawaannya.
Ketika Anda menekan
<CTRL>+<C>
Anda membunuh skrip shell, yang berperilaku normal - tetapi tidur tetap hidup. Gunakanps
untuk melihat.Ketika mencoba menghentikan hal-hal secara eksternal, melalui
kill
, maka Bash seperti di atas. Setelah beberapa periode time-out (saya kira 20 detik)launchd
kemudian mengeluarkan sebuahkill -9
script yang tidak bisa dijebak.Solusinya adalah mengeluarkan menunggu setelah tidur, untuk menunjukkan kepada Bash bahwa itu dapat mengganggu dirinya sendiri:
Ini akan memungkinkan skrip terputus, tetapi tidur masih akan bertahan. Saya yakin ada cara untuk membunuh anak-anak, tetapi saya tidak repot mencarinya ...
sumber
wait
tidak membantu (itu yang saya lakukan dalam skrip sebenarnya yang saya coba debug, saya telah mengubah contoh untuk mencocokkan sedikit lebih dekat), jadi saya tidak yakin apa yang sedang terjadi.SIGINT
, tidakINT
) akan menerima sinyal sebelum diturunkan. Tentu saja ini tidak baik untuk Mavericks, Mountain Lion dll., Tetapi ini bagus bahwa ini akhirnya berfungsi sebagaimana mestinya, jadi saya menandai ini adalah jawaban yang benar, tetapi mungkin perlu diedit karena hanya berfungsi dengan benar di bawah 10.10 .Menyadari Anda baru saja berbagi dengan kami sebuah fragmen kode dan pada dasarnya tidak jelas apa yang ingin dicapai oleh daemon selain melakukan beberapa tindakan setiap detik. Jadi saya akan membuat beberapa asumsi hanya berdasarkan apa yang Anda tulis.
Ini semua adalah masalah yang launchd dimaksudkan untuk diselesaikan dengan cara yang lebih baik di bawah Darwin (dan karenanya OS X).
Adapun pertanyaan (s) dengan membongkar dan SIGTERM, khususnya, ketika Anda
unload
launchdeamon Anda dikirim SIGKILL bukan SIGTERM. Jika Anda hanya ingin menghentikan pekerjaan atau mengirimnya SIGTERM kemudian gunakanstop
sebagai gantinyaunload
.Jika Anda ingin SIGTERM dikirim,
unload
Anda mungkin perlu mengaturEnableTransactions
. Demikian juga jika Anda memiliki tugas pembersihan dan Anda ingin deamon Anda menerima sinyal untuk pembersihan dan SIGTERM maka Anda harus menetapkanEnableTransactions
sebagai bagian dari launchd plist untuk skrip Anda.<key>EnableTransactions</key><true/>
. Ini dijelaskan dalam dokumen di https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man5/launchd.plist.5.htmlTetapi tiga mekanisme di atas tidak perlu diberikan launchd ...
Di bawah Darwin / OS X menggunakan launchdaemons, metode yang tepat untuk menerapkan sleep loop daemon adalah digunakan
StartInterval
untuk berjalan pada interval atauStartCalendarInterval
untuk menjalankan berdasarkan pada waktu tertentu. MenggunakanStartCalendarInterval
tambahan juga memberikan keuntungan bahwa ketika sistem tertidur itu akan mengeksekusi waktu interval yang terjawab alih-alih harus menunggu interval berikutnya, dan umumnya apa yang Anda inginkan dalam situasi ini. Jika Anda memiliki pekerjaan yang Anda hanya ingin tetap dipanggil, pertimbangkan juga untuk menggunakanKeepAlive
sebagai bagian dari daftar.Jadi sepertinya - dari contoh kode yang Anda berikan - Anda hanya ingin mengeksekusi sesuatu setiap 86400 detik. Jika hal ini terjadi maka launchd memiliki mekanisme untuk melakukan hal ini yang harus Anda gunakan sebagai gantinya dan meniadakan kebutuhan untuk file kunci dan perangkap sekaligus karena launchd dirancang untuk menangani semua ini untuk Anda secara otomatis. Mekanisme itu
StartInterval
dan ketika ditetapkan akan meluncurkan deamon Anda setiap N detik. Launchd juga memastikan belum meluncurkan banyak salinan daemon Anda.Mekanisme ini dijelaskan dalam dokumen launchd di https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man5/launchd.plist.5.html di mana ia menyatakan:
Jadi skrip Anda yang ter-Darwin-kan
~/Downloads/Example.sh
akan terlihat sangat sederhana sekarang seperti ini:Dan daftar Anda akan terlihat seperti ini:
Catatan Saya juga telah menyesuaikan ini untuk mengatur file logging di sini dengan cara seperti Darwin / launchd daripada dalam script itu sendiri. (Tentu saja Anda bisa menghapusnya dan menanganinya dalam skrip Anda, tetapi itu tidak perlu diberikan launchd.)
Saya perhatikan bahwa Anda juga dapat mengimplementasikan ini menggunakan
Program
seperti:Anda juga dapat menemukan http://launchd.info referensi yang berguna bersama dengan dokumen Apple untuk bagaimana launchd beroperasi di https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/ Introduction.html
Informasi tentang daemon dijalankan secara berkala dapat ditemukan di https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/ScheduledJobs.html#//apple_ref/doc/uid/10000172i-CH1-S2
sumber
launchd
akan mengirimSIGINT
ke semua agen yang menjalankan (atau lebih tepatnya, harus).EnableTransactions
true tidak akan berfungsi karena skrip shell tidak dapat memanggil perintah vproc, dan disetel ke false seharusnya menjadi default. Saya sudah mencoba memasukkannya sebagai salah untuk memastikan tetapi tampaknya tidak membantu.EnableTransactions
berfungsi untuk sinyal yang sesuai terlepas dari apakah proses tersebut benar-benar menggunakan vproc atau tidak, bahwa komentar dokumentasi pada dasarnya adalah untuk aplikasi yang sebenarnya, tetapi secara fungsional sama saja.sudo defaults write com.apple.loginwindow LogoutHook /Users/Shared/logoutHook.sh
).SIGINT
skrip saya apa adanya; apakah Anda dapat mereproduksi masalah dengan menjalankan kode contoh yang saya berikan? Pengaturan untukEnableTransactions
tampaknya tidak membuat perbedaan bagi saya.