Type= в systemd: чем отличаются simple, exec, forking, oneshot, notify
Определяет, как systemd понимает, что служба запустилась: сразу после вызова программы, после её уведомления, после завершения исходного процесса или после отработки задачи.
Что делает
Выбор типа влияет не на саму программу, а на то, когда systemd считает запуск успешным и когда начинает запускать зависимые службы. Ошибка в выборе даёт две узнаваемые картины: служба «сразу останавливается» (демонизация при simple) или «не может запуститься» по таймауту (notify у программы, которая не умеет отчитываться).
Практическое правило: если программа умеет работать на переднем плане — берите simple или exec. Если она обязательно уходит в фон — forking с PIDFile=. Если это разовая задача — oneshot. notify только для программ, которые явно поддерживают уведомления systemd.
Где ставится. В секции [Service] файла службы. Значение по умолчанию — simple, если задан ExecStart=, и oneshot, если он не задан.
Значения
| Значение | Что происходит |
|---|---|
simple | запуск считается успешным сразу после вызова программы. Зависимые службы стартуют, не дожидаясь готовности. |
exec | то же, но systemd ждёт успешного вызова execve(): ошибки запуска (неверный путь, нет прав) видны сразу как неудача запуска, а не как падение позже. |
forking | программа уходит в фон и завершает исходный процесс. Нужен PIDFile=, иначе systemd будет угадывать главный процесс. |
oneshot | задача отрабатывает и завершается. Разрешено несколько ExecStart=. Обычно вместе с RemainAfterExit=yes. |
notify | systemd ждёт от программы уведомления о готовности. Без поддержки в программе запуск закончится таймаутом. |
notify-reload | как notify, плюс программа сообщает о завершении перезагрузки настроек. Доступно с systemd 253. |
dbus | служба считается запущенной, когда занимает имя из BusName= на шине. |
idle | запуск откладывается до затихания остальных заданий. Нужен редко, в основном для аккуратного вывода на консоль. |
По умолчанию: simple при заданном ExecStart=
Пример
Обычная служба на переднем плане и разовая задача.
[Service]
Type=exec
ExecStart=/usr/local/bin/myapp --listen 127.0.0.1:8080
# разовая задача: отработала и осталась «выполненной»
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/migrate.sh
Тип exec предпочтительнее simple там, где важно сразу узнать об ошибке запуска: он ждёт фактического вызова программы.
Типичные ошибки
Демонизирующаяся программа при Type=simple даёт состояние «inactive (dead)» с кодом 0: systemd счёл службу отработавшей. Либо отключайте демонизацию, либо ставьте forking с PIDFile=.
Type=notify у программы без поддержки уведомлений всегда заканчивается таймаутом запуска, даже когда программа исправно работает.
Type=oneshot вместе с Restart=always уходит в цикл перезапусков и упирается в предел частоты запусков.
Type=forking без PIDFile= заставляет systemd угадывать главный процесс; угадывание часто ошибается, и остановка задевает не тот процесс.
Связанные ошибки
- status=0/SUCCESS, но служба считается упавшейПрограмма завершилась успешно, а systemctl показывает inactive или failed. Разбор: Type=simple против forking, RemainAfterExit, демонизация.
- Failed with result 'protocol'Состояние protocol: служба нарушила договор со systemd. Обычно Type=notify без уведомления или Type=dbus без имени на шине.
- Failed with result 'timeout'Состояние timeout: служба не уложилась в отведённое время при запуске, остановке или перезагрузке настроек.
- Job for … failed because a timeout was exceededЗадание на запуск прервано по таймауту. Как отличить медленный старт от заблокированного и правильно настроить TimeoutStartSec.
Рядом стоящие параметры
Где важен на практике
Источники
- systemd.service(5)
- Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)