Налаштуйте службову систему buggy для завершення через SIGKILL


20

Фон

Мене попросили створити systemdсценарій для нової послуги, foo_daemonяка іноді потрапляє у "поганий стан", і не загине SIGTERM(можливо, через користувальницький обробник сигналу). Це проблематично для розробників, оскільки їм доручено запустити / зупинити / перезапустити службу через:

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

Проблема

Іноді, через foo_daemonпотрапляння в поганий стан, нам доводиться насильно вбивати його через:

  • systemctl kill -s KILL foo_daemon.service

Питання

Як я можу налаштувати свій systemdскрипт, foo_daemonщоб кожен раз, коли користувач намагався зупинити / перезапустити послугу systemd:

  • Спроба граціозного відключення програми foo_daemonvia SIGTERM.
  • Дайте до 2 секунд, щоб завершити відключення / припинення foo_daemon.
  • Спроба примусового відключення з foo_daemonдопомогою , SIGKILLякщо процес все ще живий (так що ми не маємо ризик PID переробляються і systemdпитання SIGKILLвід неправильного PID). Пристрій, на якому ми швидко тестуємо нерести / вилки, виконує численні процеси, тому виникає рідкісна, але дуже реальна стурбованість переробкою PID, що викликає проблеми.
  • Якщо на практиці я просто параноїзуюсь щодо переробки PID, я все в порядку, коли сценарій видається SIGKILLпроти PID процесу, не переймаючись вбивством переробленого PID.


2
Навіть якщо ви нерестуєте процеси досить швидко, щоб прокрутити понад 4 мільйони PID за дві секунди, systemd не сидить у циклі, перевіряючи "чи цей підручник ще живий? Чи цей підручник ще живий?" тому що це не потрібно ; він уже повідомляється про те, чи живі його найближчі процеси все ще живі чи ні (за допомогою звичайного SIGCHLD і невдалого ()). Тож якщо він побачить, що процес, який закінчився після SIGTERM, він просто позначить послугу як "неактивну" в цей момент - він взагалі не буде турбуватися з перевіркою, очікуванням та відправленням SIGKILL.
grawity

Відповіді:


26

systemd вже підтримує це у вікні, і він включений за замовчуванням .

Єдине, що ви можете налаштувати - це час очікування, який ви можете зробити TimeoutStopSec=. Наприклад:

[Service]
TimeoutStopSec=2

Тепер systemd надішле SIGTERM, зачекає дві секунди, поки сервіс вийде, і якщо цього не відбудеться, він надішле SIGKILL.

Якщо ваша служба не обізнана з системою, вам може знадобитися надати шлях до її PID-файлу PIDFile=.

Нарешті, ви згадали, що ваш демон породжує багато процесів. У цьому випадку ви, можливо, захочете встановити, KillMode=control-groupа systemd буде надсилати сигнали всім процесам у групі.


Дякую. Останнє питання: припустимо, що послуга не обізнана з системою. Що я можу додати до системного сценарію для цієї послуги, щоб systemd створював / керував файлом PID? Крім того, сервіс може бути багатопримірником через шаблонні одиниці, тому ми зазвичай запускаємо його через `systemctl start foo_dameon@1.service", так що це вплине на логіку файлу PID у сценарії?
Хмара

4
@DevNull systemd не створює та не керує файлами PID. Для цього немає ніяких причин. Якщо ваша служба не створює власний PID-файл, то, якщо можливо, налаштуйте його для запуску на передньому плані (замість демонстрації) та встановлення Type=simpleв системному блоці.
Майкл Хемптон

1
Якщо служба має залежних, Type=forkingмає перевагу (якщо служба була належним чином написана), щоб повідомити systemd, коли він повністю "готовий", що Type = simple не може зробити. Демонізування не є проблемою, навіть без файлу PID - systemd все одно відстежує основний процес.
grawity

1
@grawity Досить правдиво ... хоча мій досвід, що служби демонізуються ще до того, як вони насправді готові почати обслуговувати. Служба, що обізнана з системою Type=notify, найкраще використовується для системних систем, і багато поширених сервісів це вже роблять. Але, мабуть, не ця спадщина послуга. У випадку з ОП він має службу, яка породжує багато процесів. Документи systemd попереджають про цю справу .
Майкл Хемптон

1

Оскільки ніхто не згадав про необхідність Type=oneshot, ось повний приклад, який виходить із-за помилки в очікуванні.

[Unit]
Description=timeout test

[Service]
Type=oneshot
TimeoutStartSec=2
ExecStart=/bin/sleep 10
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.