Konfigurasikan layanan systemd buggy untuk diakhiri melalui SIGKILL

20

Latar Belakang

Saya diminta untuk membuat systemdskrip untuk layanan baru foo_daemon,, yang terkadang masuk ke "kondisi buruk", dan tidak akan mati melalui SIGTERM(kemungkinan karena penangan sinyal khusus). Ini bermasalah bagi pengembang, karena mereka diperintahkan untuk memulai / menghentikan / memulai kembali layanan melalui:

  • systemctl start foo_daemon.service
  • systemctl stop foo_daemon.service
  • systemctl restart foo_daemon.service

Masalah

Terkadang, karena foo_daemonmasuk ke kondisi buruk, kita harus membunuhnya secara paksa melalui:

  • systemctl kill -s KILL foo_daemon.service

Pertanyaan

Bagaimana saya dapat mengatur systemdskrip saya foo_daemonsehingga, setiap kali pengguna mencoba menghentikan / memulai kembali layanan, systemdakan:

  • Mencoba shutdown foo_daemonvia SIGTERM.
  • Berikan hingga 2 detik untuk shutdown / terminasi foo_daemonhingga selesai.
  • Coba shutdown paksa foo_daemonmelalui SIGKILLjika proses masih hidup (jadi kami tidak memiliki risiko PID didaur ulang dan systemdmasalah SIGKILLterhadap PID yang salah). Perangkat yang kami uji memunculkan / memalsukan banyak proses dengan cepat, sehingga ada kekhawatiran yang jarang namun sangat nyata tentang daur ulang PID yang menyebabkan masalah.
  • Jika, dalam praktiknya, saya hanya menjadi paranoid tentang daur ulang PID, saya setuju dengan skrip yang hanya SIGKILLmenentang proses PID tanpa khawatir akan membunuh PID daur ulang.

Awan
sumber
2
Bahkan jika Anda menelurkan proses cukup cepat untuk memutar lebih dari 4 juta PID dalam dua detik, systemd tidak duduk dalam satu lingkaran memeriksa "apakah pid ini masih hidup? Apakah pid ini masih hidup?" karena tidak perlu ; sudah diinformasikan tentang apakah proses anak langsungnya masih hidup atau tidak (melalui SIGCHLD biasa dan waitpid ()). Jadi jika melihat bahwa proses keluar setelah SIGTERM, itu hanya akan menandai layanan sebagai 'tidak aktif' pada saat itu - tidak akan repot dengan memeriksa, menunggu, dan mengirim SIGKILL sama sekali.
grawity

Jawaban:

26

systemd sudah mendukung ini di luar kotak, dan itu diaktifkan secara default .

Satu-satunya hal yang Anda ingin sesuaikan adalah batas waktu, yang dapat Anda lakukan dengan TimeoutStopSec=. Sebagai contoh:

[Service]
TimeoutStopSec=2

Sekarang, systemd akan mengirim SIGTERM, menunggu dua detik hingga layanan keluar, dan jika tidak, ia akan mengirim SIGKILL.

Jika layanan Anda tidak sadar sistem, Anda mungkin perlu menyediakan path ke file PID-nya PIDFile=.

Akhirnya, Anda menyebutkan bahwa daemon Anda memunculkan banyak proses. Dalam hal ini, Anda mungkin ingin mengatur KillMode=control-groupdan systemd akan mengirim sinyal ke semua proses di cgroup.

Michael Hampton
sumber
Terima kasih. Satu pertanyaan terakhir: mari kita asumsikan layanan ini tidak sadar sistem. Apa yang bisa saya tambahkan ke skrip systemd untuk layanan ini sehingga systemd membuat / mengelola file PID? Selain itu, layanan dapat multi-instance melalui unit template, jadi kami biasanya meluncurkannya melalui `systemctl start [email protected]", jadi apakah itu berdampak pada logika file PID dalam skrip?
Cloud
4
@DevNull systemd tidak membuat atau mengelola file PID. Tidak ada alasan untuk melakukannya. Jika layanan Anda tidak membuat file PID sendiri, maka jika mungkin konfigurasikan untuk berjalan di latar depan (bukan daemonisasi) dan atur Type=simpledalam unit systemd.
Michael Hampton
1
Jika layanan memiliki tanggungan, Type=forkingmemiliki keunggulan (jika layanan ditulis dengan benar) memberi tahu systemd ketika sepenuhnya 'siap' yang Tipe = sederhana tidak dapat lakukan. Daemonisasi bukanlah masalah, bahkan tanpa file PID - systemd akan melacak proses utamanya.
grawity
1
@grawity Benar saja ... meskipun sudah pengalaman saya bahwa layanan mendemonstrasikan sebelum mereka benar-benar siap untuk mulai melayani. Penggunaan sistem-sadar menggunakan Type=notifyterbaik untuk systemd, dan banyak layanan umum sudah melakukan ini. Tapi mungkin bukan layanan warisan ini. Dalam kasus OP, ia memiliki layanan yang memunculkan banyak proses. Systemd docs memperingatkan tentang kasus ini .
Michael Hampton
1

Karena tidak ada yang menyebutkan perlu Type=oneshot, berikut adalah contoh lengkap yang keluar karena kegagalan waktu habis.

[Unit]
Description=timeout test

[Service]
Type=oneshot
TimeoutStartSec=2
ExecStart=/bin/sleep 10
Evidlo
sumber