Mengapa "proses tidak boleh bercabang" untuk layanan tipe sederhana di systemd?
Saya ingin menulis systemd
file unit saya sendiri untuk mengelola perintah 1 yang berjalan sangat lama (dalam urutan jam). Saat melihat artikel ArchWiki di systemd , dikatakan hal berikut tentang memilih jenis start up:
Type=simple
(default): systemd menganggap layanan akan segera dimulai. Prosesnya tidak boleh bercabang . Jangan gunakan jenis ini jika layanan lain perlu dipesan pada layanan ini, kecuali jika soket diaktifkan.
Mengapa prosesnya tidak bercabang sama sekali? Apakah ini mengacu pada percabangan dalam gaya proses pemanggilan daemon (percabangan induk, lalu keluar), atau percabangan apa pun?
1 Saya tidak ingin tmux / screen karena saya ingin cara yang lebih elegan untuk memeriksa status dan memulai ulang layanan tanpa menggunakan tmux send-keys
.
Jawaban
Layanan diizinkan untuk memanggil panggilan fork
sistem. Systemd tidak akan mencegahnya, atau bahkan menyadarinya jika memang demikian. Kalimat ini secara khusus merujuk pada praktik percabangan di awal daemon untuk mengisolasi daemon dari proses induknya. "Proses tidak boleh bercabang [dan keluar dari induk saat menjalankan layanan dalam proses anak]".
The halaman manual menjelaskan ini lebih verbosely, dan dengan kata-kata yang tidak menimbulkan kebingungan tertentu.
Banyak program yang dimaksudkan untuk digunakan sebagai daemon memiliki mode (seringkali mode default) di mana ketika mereka mulai, mereka mengisolasi diri dari induknya. Daemon dimulai, memanggil fork()
, dan keluar induk. Proses anak memanggil setsid()
sehingga berjalan dalam grup proses dan sesinya sendiri, dan menjalankan layanan. Tujuannya adalah jika daemon dipanggil dari baris perintah shell, daemon tidak akan menerima sinyal apa pun dari kernel atau dari shell bahkan jika sesuatu terjadi pada terminal seperti penutupan terminal (dalam hal ini shell mengirimkan SIGHUP untuk semua grup proses yang diketahui). Hal ini juga menyebabkan proses servis diadopsi oleh init, yang akan menuai ketika keluar, menghindari zombie jika daemon dimulai oleh sesuatu yang tidak akan wait()
melakukannya (ini tidak akan terjadi jika daemon dimulai oleh shell ).
Ketika daemon dimulai dengan proses pemantauan seperti systemd, forking menjadi kontraproduktif. Proses pemantauan seharusnya memulai ulang layanan jika macet, jadi perlu diketahui apakah layanan keluar, dan itu sulit jika layanan bukan turunan langsung dari proses pemantauan. Proses pemantauan seharusnya tidak pernah mati dan tidak memiliki terminal pengendali, jadi tidak ada kekhawatiran seputar sinyal yang tidak diinginkan atau tuai. Jadi tidak ada alasan untuk proses layanan untuk tidak menjadi anak monitor, dan ada alasan bagus untuk itu.
Abaikan halaman wiki Arch ini.
Ada hal-hal yang sangat salah sehubungan dengan Type
pengaturannya. simple
Apalagi ini tidak hanya terbatas pada deskripsinya saja . Apa yang dikatakannya forking
salah juga.
Rekomendasi yang tepat untuk hal semacam ini telah ada selama beberapa dekade lebih lama daripada systemd itu sendiri, dan kembali ke setidaknya awal 1990-an. Seperti yang saya catat dihttps://unix.stackexchange.com/a/476608/5132, di systemd doco ada versi Johnny-come-recent dari rekomendasi untuk demon yang sebagian besar mengulangi apa yang pengguna daemontools, IBM, orang-orang yang menggunakan inittab
, dan… well… telah saya katakan selama beberapa dekade. (Itu sudah menjadi jawaban yang sering diberikan ketika saya menulisnya seperti itu pada tahun 2001.)
Mengulang:
Jika program Anda memiliki beberapa mekanisme "dæmonization", yang secara khusus memisahkan anak dan keluar dari proses induk, matikan dan jangan gunakan . Terima kasih kepada daemontools dkk. di mana ini telah menjadi persyaratan untuk waktu yang lama, banyak program telah mengembangkan kemampuan untuk tidak memiliki mekanisme seperti itu dalam lebih dari 20 tahun terakhir, dan yang lainnya tidak secara default untuk "mendemonstrasikan" di tempat pertama sehingga dapat digunakan di mode operasi default mereka.
Subsistem manajemen layanan telah meluncurkan proses layanan dalam konteks demon . Proses tersebut tidak perlu "mendemonstrasikan". (Memang, itu adalah kesalahan pada banyak sistem operasi modern untuk berpikir bahwa program bahkan dapat "dæmonize" dari konteks sesi login, yang sebenarnya tentang "dæmonization".) Mereka sudah memiliki nilai lingkungan, dan deskriptor file terbuka, sesuai dengan konteks demon, dan beberapa hal yang dilakukan oleh "demonization" sebenarnya menggagalkan beberapa hal konvensional yang biasa dilakukan dengan demon (misalnya menangkap output / kesalahan standar mereka ke dalam log) oleh manajer layanan.
Lebih suka Type=simple
, dengan pembukaan soket awal (di mana manajemen layanan membuka soket server dan meneruskannya sebagai deskriptor file yang sudah terbuka ke program layanan), atau Type=notify
.
Type=simple
memperlakukan layanan sebagai siap (sehingga layanan yang dipesan di atasnya dapat dimulai / dihentikan) segera setelah proses layanan dimulai, dengan pembukaan soket awal menggunakan semantik koneksi soket untuk menunda klien layanan, pada titik-titik yang mereka coba sambungkan ke server untuk layanan, hingga server benar-benar siap.Type=notify
memiliki kerugian menjadi khas systemd dan Linux (di samping masalah tidak berfungsi dari proses berumur pendek seperti pemijahan shellsystemd-notify
, dan menggunakan penguraian bentuk yang dapat dibaca manusia menjadi bentuk yang dapat dibaca mesin dalam proses istimewa, di mana masalah parser telah terjadi di masa lalu) tetapi memiliki keuntungan dalam memberikan kontrol yang lebih baik (dari sudut pandang program layanan) ketika layanan benar-benar dianggap siap. Ini juga memungkinkan beberapa penyesuaian keluaran status.
Program layanan, dari kedua jenis, dapat bercabang. Itu bercabang dan kemudian keluar dari proses asli itulah masalahnya.
(Perlu dicatat bahwa ini adalah masalah untuk menjalankan program dari shell seperti halnya untuk menjalankan program dari manajer layanan, dengan pengguna melihat program berhenti dan menyebabkan shell prompt lain hampir seketika. Memang, baru hari ini seseorang bertanya, lagi-lagi , tentang menjalankan program dari shell yang bercabang dan keluar dari induk, di Mengapa kadang-kadang ketika saya menjalankan program di terminal, itu tidak akan berjalan di terminal?. )
Type=oneshot
mungkin bukan yang Anda inginkan dalam kasus khusus ini, karena layanan dianggap siap hanya jika seluruh program layanan telah berjalan hingga selesai. Ada kegunaannya, tetapi dari bunyinya itu tidak berlaku untuk Anda.
Jangan pernah gunakan Type=forking
. Ini harus menjadi pilihan terakhir dari keputusasaan, karena hampir tidak ada program yang benar-benar menggunakan protokol . Mereka melakukan sesuatu yang lain , yang sebenarnya bukan protokol ini, tidak dapat dioperasikan dengan benar dengan protokol ini, dan bukan kesiapan pensinyalan.
Bacaan lebih lanjut
- Jonathan de Boyne Pollard (2001). Kesalahan yang harus dihindari saat merancang program daemon Unix . Jawaban yang Sering Diberikan.
- Jonathan de Boyne Pollard (2015). Anda benar-benar tidak perlu melakukan daemonisasi. Betulkah. . Rumah Horor systemd.
- Jonathan de Boyne Pollard (2015). Masalah protokol kesiapan dengan Unix dæmons . Jawaban yang Sering Diberikan.
- https://unix.stackexchange.com/a/401611/5132