man/systemd.service: advise Type=exec instead of Type=simple

The descriptions of various options are reworked: first say what protocol
actually is, i.e. describe what type of notification the manager waits
for. Only after that describe various steps and things the service should
do. Also, apply some paragraph breaks.

Instead of recommending Type=simple, recommend Type=exec. Say explicitly that
Type=simple, Type=forking are not recommended. Type=simple ignores failure in a
way that doesn't make any sense except as a historical accident. We introduced
'exec' instead of changing 'simple' to keep backwards-compatiblity, but
'simple' is not very useful. 'forking' works, but is inefficient: correctly
programming the interface requires a lot of work, and at runtime, the
additional one or two forks are just a waste of CPU resources. Furthermore, we
now understand that because of COW traps, they may also increase memory
requirements. There is really no reason to use 'forking', except if it's
already implemented and the code cannot be changed to use 'notify'.

Also, remove the recommendations to use Type=simple to avoid delaying boot. In
most cases, if the service can support notifications about startup, those
should be done.

Overall, for new services, "notify", "notify-reload", and "dbus" are the
types that make sense.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2023-07-30 12:11:33 +02:00
parent ffe7ddb9bc
commit 377d3a31e6

View file

@ -155,41 +155,52 @@
<term><varname>Type=</varname></term>
<listitem>
<para>Configures the process start-up type for this service unit. One of <option>simple</option>,
<option>exec</option>, <option>forking</option>, <option>oneshot</option>, <option>dbus</option>,
<option>notify</option>, <option>notify-reload</option> or <option>idle</option>:</para>
<para>Configures the mechanism via which the service notifies the manager that the service start-up
has finished. One of <option>simple</option>, <option>exec</option>, <option>forking</option>,
<option>oneshot</option>, <option>dbus</option>, <option>notify</option>,
<option>notify-reload</option>, or <option>idle</option>:</para>
<itemizedlist>
<listitem><para>If set to <option>simple</option> (the default if <varname>ExecStart=</varname> is
specified but neither <varname>Type=</varname> nor <varname>BusName=</varname> are), the service manager
will consider the unit started immediately after the main service process has been forked off. It is
expected that the process configured with <varname>ExecStart=</varname> is the main process of the
service. In this mode, if the process offers functionality to other processes on the system, its
communication channels should be installed before the service is started up (e.g. sockets set up by
systemd, via socket activation), as the service manager will immediately proceed starting follow-up units,
right after creating the main service process, and before executing the service's binary. Note that this
means <command>systemctl start</command> command lines for <option>simple</option> services will report
success even if the service's binary cannot be invoked successfully (for example because the selected
<varname>User=</varname> doesn't exist, or the service binary is missing).</para></listitem>
will consider the unit started immediately after the main service process has been forked off.
<emphasis>The use of this type is discouraged, use <option>exec</option> instead.
</emphasis></para>
<listitem><para>The <option>exec</option> type is similar to <option>simple</option>, but the service
manager will consider the unit started immediately after the main service binary has been executed. The service
manager will delay starting of follow-up units until that point. (Or in other words:
<option>simple</option> proceeds with further jobs right after <function>fork()</function> returns, while
<option>exec</option> will not proceed before both <function>fork()</function> and
<function>execve()</function> in the service process succeeded.) Note that this means <command>systemctl
start</command> command lines for <option>exec</option> services will report failure when the service's
binary cannot be invoked successfully (for example because the selected <varname>User=</varname> doesn't
<para>It is expected that the process configured with <varname>ExecStart=</varname> is the main
process of the service. In this mode, if the process offers functionality to other processes on
the system, its communication channels should be installed before the service is started up
(e.g. sockets set up by systemd, via socket activation), as the service manager will immediately
proceed starting follow-up units, right after creating the main service process, and before
executing the service's binary. Note that this means <command>systemctl start</command> command
lines for <option>simple</option> services will report success even if the service's binary
cannot be invoked successfully (for example because the selected <varname>User=</varname> doesn't
exist, or the service binary is missing).</para></listitem>
<listitem><para>If set to <option>forking</option>, it is expected that the process configured with
<varname>ExecStart=</varname> will call <function>fork()</function> as part of its start-up. The parent
process is expected to exit when start-up is complete and all communication channels are set up. The child
continues to run as the main service process, and the service manager will consider the unit started when
the parent process exits. This is the behavior of traditional UNIX services. If this setting is used, it is
recommended to also use the <varname>PIDFile=</varname> option, so that systemd can reliably identify the
main process of the service. systemd will proceed with starting follow-up units as soon as the parent
process exits.</para></listitem>
<listitem><para>The <option>exec</option> type is similar to <option>simple</option>, but the
service manager will consider the unit started immediately after the main service binary has been
executed. The service manager will delay starting of follow-up units until that point. (Or in
other words: <option>simple</option> proceeds with further jobs right after
<function>fork()</function> returns, while <option>exec</option> will not proceed before both
<function>fork()</function> and <function>execve()</function> in the service process succeeded.)
Note that this means <command>systemctl start</command> command lines for <option>exec</option>
services will report failure when the service's binary cannot be invoked successfully (for
example because the selected <varname>User=</varname> doesn't exist, or the service binary is
missing).</para></listitem>
<listitem><para>If set to <option>forking</option>, the manager will consider the unit started
immediately after the binary that forked off by the manager exits. <emphasis>The use of this type
is discouraged, use <option>notify</option>, <option>notify-reload</option>, or
<option>dbus</option> instead.</emphasis></para>
<para>It is expected that the process configured with <varname>ExecStart=</varname> will call
<function>fork()</function> as part of its start-up. The parent process is expected to exit when
start-up is complete and all communication channels are set up. The child continues to run as the
main service process, and the service manager will consider the unit started when the parent
process exits. This is the behavior of traditional UNIX services. If this setting is used, it is
recommended to also use the <varname>PIDFile=</varname> option, so that systemd can reliably
identify the main process of the service. The manager will proceed with starting follow-up units
after the parent process exits.</para></listitem>
<listitem><para>Behavior of <option>oneshot</option> is similar to <option>simple</option>;
however, the service manager will consider the unit up after the main process exits. It will then
@ -197,18 +208,19 @@
of service. <varname>Type=</varname><option>oneshot</option> is the implied default if neither
<varname>Type=</varname> nor <varname>ExecStart=</varname> are specified. Note that if this
option is used without <varname>RemainAfterExit=</varname> the service will never enter
<literal>active</literal> unit state, but directly transition from <literal>activating</literal>
to <literal>deactivating</literal> or <literal>dead</literal> since no process is configured that
shall run continuously. In particular this means that after a service of this type ran (and which
has <varname>RemainAfterExit=</varname> not set) it will not show up as started afterwards, but
as dead.</para></listitem>
<literal>active</literal> unit state, but will directly transition from
<literal>activating</literal> to <literal>deactivating</literal> or <literal>dead</literal>,
since no process is configured that shall run continuously. In particular this means that after a
service of this type ran (and which has <varname>RemainAfterExit=</varname> not set) it will not
show up as started afterwards, but as dead.</para></listitem>
<listitem><para>Behavior of <option>dbus</option> is similar to <option>simple</option>; however,
it is expected that the service acquires a name on the D-Bus bus, as configured by
<varname>BusName=</varname>. systemd will proceed with starting follow-up units after the D-Bus
bus name has been acquired. Service units with this option configured implicitly gain
dependencies on the <filename>dbus.socket</filename> unit. This type is the default if
<varname>BusName=</varname> is specified. A service unit of this type is considered to be in the
units of this type must have the <varname>BusName=</varname> specified and the service manager
will consider the unit up when the specified bus name has been acquired. This type is the default
if <varname>BusName=</varname> is specified.</para>
<para>Service units with this option configured implicitly gain dependencies on the
<filename>dbus.socket</filename> unit. A service unit of this type is considered to be in the
activating state until the specified bus name is acquired. It is considered activated while the
bus name is taken. Once the bus name is released the service is considered being no longer
functional which has the effect that the service manager attempts to terminate any remaining
@ -223,15 +235,19 @@
units after this notification message has been sent. If this option is used,
<varname>NotifyAccess=</varname> (see below) should be set to open access to the notification
socket provided by systemd. If <varname>NotifyAccess=</varname> is missing or set to
<option>none</option>, it will be forcibly set to <option>main</option>.</para></listitem>
<option>none</option>, it will be forcibly set to <option>main</option>.</para>
<listitem><para>Behavior of <option>notify-reload</option> is identical to
<option>notify</option>. However, it extends the logic in one way: the
<constant>SIGHUP</constant> UNIX process signal is sent to the service's main process when the
service is asked to reload. (The signal to send can be tweaked via
<varname>ReloadSignal=</varname>, see below.) When
initiating the reload process the service is then expected to reply with a notification message
via <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
<para>If the service supports reloading, and uses the a signal to start the reload, using
<option>notify-reload</option> instead is recommended.</para></listitem>
<listitem><para>Behavior of <option>notify-reload</option> is similar to <option>notify</option>,
with one difference: the <constant>SIGHUP</constant> UNIX process signal is sent to the service's
main process when the service is asked to reload and the manager will wait for a notification
about the reload being finished.</para>
<para>When initiating the reload process the service is expected to reply with a notification
message via
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
that contains the <literal>RELOADING=1</literal> field in combination with
<literal>MONOTONIC_USEC=</literal> set to the current monotonic time
(i.e. <constant>CLOCK_MONOTONIC</constant> in
@ -239,7 +255,10 @@
in μs, formatted as decimal string. Once reloading is complete another notification message must
be sent, containing <literal>READY=1</literal>. Using this service type and implementing this
reload protocol is an efficient alternative to providing an <varname>ExecReload=</varname>
command for reloading of the service's configuration.</para></listitem>
command for reloading of the service's configuration.</para>
<para>The signal to send can be tweaked via <varname>ReloadSignal=</varname>, see below.</para>
</listitem>
<listitem><para>Behavior of <option>idle</option> is very similar to <option>simple</option>; however,
actual execution of the service program is delayed until all active jobs are dispatched. This may be used
@ -249,27 +268,25 @@
anyway.</para></listitem>
</itemizedlist>
<para>It is generally recommended to use <varname>Type=</varname><option>simple</option> for
<para>It is generally recommended to use <varname>Type=</varname><option>exec</option> for
long-running services whenever possible, as it is the simplest and fastest option. However, as this
service type won't propagate service start-up failures and doesn't allow ordering of other units
against completion of initialization of the service (which for example is useful if clients need to
connect to the service through some form of IPC, and the IPC channel is only established by the
service itself — in contrast to doing this ahead of time through socket or bus activation or
similar), it might not be sufficient for many cases. If so, <option>notify</option>,
<option>notify-reload</option> or <option>dbus</option> (the latter only in case the service
<option>notify-reload</option>, or <option>dbus</option> (the latter only in case the service
provides a D-Bus interface) are the preferred options as they allow service program code to
precisely schedule when to consider the service started up successfully and when to proceed with
follow-up units. The <option>notify</option>/<option>notify-reload</option> service types require
explicit support in the service codebase (as <function>sd_notify()</function> or an equivalent API
needs to be invoked by the service at the appropriate time) — if it's not supported, then
<option>forking</option> is an alternative: it supports the traditional UNIX service start-up
protocol. Finally, <option>exec</option> might be an option for cases where it is enough to ensure
the service binary is invoked, and where the service binary itself executes no or little
initialization on its own (and its initialization is unlikely to fail). Note that using any type
other than <option>simple</option> possibly delays the boot process, as the service manager needs
to wait for service initialization to complete. It is hence recommended not to needlessly use any
types other than <option>simple</option>. (Also note it is generally not recommended to use
<option>idle</option> or <option>oneshot</option> for long-running services.)</para>
<option>forking</option> is an alternative: it supports the traditional heavy-weight UNIX service
start-up protocol. Note that using any type other than
<option>simple</option>/<option>exec</option> possibly delays the boot process, as the service
manager needs to wait for service initialization to complete. (Also note it is generally not
recommended to use <option>idle</option> or <option>oneshot</option> for long-running services.)
</para>
</listitem>
</varlistentry>