Services and daemons

When creating snapcraft.yaml to build a new snap, a snap’s executable component can be either exposed as a command or run as a background service or daemon.

For details on how to expose an executable from its constituent parts, see Defining a command.

A snap daemon or service behaves the same as a native daemon or service, and will either start automatically at boot time and end when the machine is shutdown, or start and stop on demand through socket activation.

Snap confinement prohibits a system’s users and groups from running as traditional services might, such as under a user’s ownership. But a daemon user and group can alternatively be created within a snap to provide similar user and group level control outside of a snap’s confinement. See System usernames for more details.

See Service management for details on starting and stopping services from the snap command. Services and daemons can also be managed from within a snap, such as via a hook, with the snapctl.

To set memory and CPU resource limits for a service or daemon, see Quota groups

If you need to add user configurable options to your service or daemon, such as which port it should use, see Adding snap configuration.

Defining a daemon

To define an executable as a daemon or service, add daemon: simple to its apps stanza:

apps:
  part-os-release:
    command: bin/os-release.sh
    daemon: simple

The value for daemon: can be one of the following:

  • simple Run for as along as the service is active - this is typically the default option.
  • oneshot Run once and exit after completion, notifying systemd. After completion, the daemon is still considered active and running.
  • forking The configured command calls fork() as part of its start-up and the parent process is then expected to exit when start-up is complete. This isn’t the recommended behaviour on a modern Linux system.
  • notify Assumes the command will send a signal to systemd to indicate its running state. Note this requires usage of the daemon-notify interface.

In addition to the above types of daemon or service, the following can be set to help manage how a service is run, how it can be stopped, and what should happen after it stops:

  • after An ordered list of applications the daemon is to be started after. Applications must be part of the same snap.
  • before An ordered list of applications the daemon is to be started before. Applications must be part of the same snap.
  • install-mode Defines whether a freshly installed daemon is started automatically, or whether startup control is deferred to the snap. The snap could then use snapctl with a hook, for instance, or another management agent. Can be enable (default) or disable.
  • post-stop-command Sets the command to run from inside the snap after a service stops.
  • refresh-mode Controls whether a daemon should be restarted during a snap refresh. Can be either restart , endure, (do not restart) or ignore-running (does not refresh running services to facilitate the refresh app awareness feature). Defaults to restart .
  • reload-command Defines the command within the snap to be executed when a service needs to be restarted or reloaded after a configuration change, as initiated with the snap restart --reload command.
    Example: reload-command: sbin/nginx -s reload
  • restart-condition Defines when a service should be restarted, using values returned from systemd service exit status. Can be one of [on-failure|on-success|on-abnormal|on-abort|on-watchdog|always|never].
  • restart-delay The delay between service restarts. Defaults to unset. See the systemd.service manual on RestartSec for details. Time duration units can be 10ns, 10us, 10ms, 10s, 10m.
  • sockets Requires an activated daemon socket, and works with the network-bind interface to map a daemon’s socket to a service and activate it.
  • socket-mode The mode of a socket in octal.
  • start-timeout Optional time to wait for daemon to start. Time duration units can be 10ns, 10us, 10ms, 10s, 10m.
  • stop-command An optional executable command to run before the daemon is stopped, and the daemon is not stopped until the specified stop-command terminates. This can be to used to gracefully handle a daemon stop or restart, such as when a refresh happens, by allowing the daemon to reach a stoppable state first.
  • stop-mode Defines which termination signal to use when stopping the daemon. Can be one of either sigterm, sigterm-all, sighup, sighup-all, sigusr1, sigusr1-all, sigusr2, sigusr2-all, sigint and sigint-all .
  • stop-timeout The length of time to wait before terminating a service. Time duration units can be 10ns, 10us, 10ms, 10s, 10m. Termination is via SIGTERM (and SIGKILL if that doesn’t work).
  • timer Declares that the service is activated by a timer and that the app must be a daemon. See Timer string format for syntax examples.
  • watchdog-timeout This value declares the service watchdog timeout. For watchdog to work, the application requires access to the systemd notification socket, which can be declared by listing a daemon-notify plug in the plugs section. Time duration units can be 10ns, 10us, 10ms, 10s, 10m.

For further details, see Snapcraft app and service metadata.

Daemons and D-Bus

Daemons can configured to interact with D-Bus in a number of ways. D-Bus can be used to indicate to systemd that a daemon is running, it can be used as the mechanism to activate a daemon, and it can be used generally to expose services to applications.

D-Bus activation can only be used for services on the system bus.

Daemon type

The daemon keyword is used to specify the type of a daemon and the mechanism it uses to inform systemd that it is running.

A daemon can be configured to use D-Bus to notify systemd that it is running by claiming a D-Bus name. This behaviour is enabled by setting the daemon keyword to a value of dbus in the app metadata.

Daemons that use D-Bus in other ways that do not need this feature can set the daemon type to a value other than dbus. This enables other methods to be used to indicate to systemd that they are running.

If the dbus type is used, either the bus-name keyword or activates-on keyword must be used to define a bus name for the daemon. If both keywords are defined, the bus name takes precedence. If only the activates-on keyword is defined, the last name in its list of slots is used as the bus name.

Activation

The activates-on keyword is used to define a list of names that will be exposed via D-Bus. These names are automatically added to the slots for the snap.

This provides a way for a daemon to be started on a D-Bus method call. When a method on any of the names is invoked, the daemon’s command is run to start the daemon.

General use

A daemon that needs to provide services to applications can be configured to use a bus name by setting its bus-name keyword. This enables the system bus to be used for communication, as with regular system daemons.

As noted above, the daemon keyword does not need to specify the dbus type for this use case, unless it is convenient to notify systemd about start-up by claiming a D-Bus name.

This link is broken, it doesn’t point anywhere, it doesn’t have a href attribute; it should point to https://snapcraft.io/docs/snapcraft-app-and-service-metadata

Thanks for letting us know - there was a typo in the URL metadata.

Assumes the command will send a signal to systemd to indicate that it’s running state. Note this requires usage of the daemon-notify interface.

I think the author updated this but didn’t re-read: "to indicate that it’s running state"_
Should likely be:

Assumes the command will send a signal to systemd to indicate its running state. Note this requires usage of the daemon-notify interface.

Or

Assumes the command will send a signal to systemd to indicate that it’s running. Note this requires usage of the daemon-notify interface.

Thank you!! I’ve just updated the doc with your fix.

2 Likes

Please sanity check me on this, but if I am reading correctly it looks like the description on before and after are wrong.

Based on these descriptions, I would expect the output on the log to be sequenced early middle late However, in reality it goes late middle early.

Digging a little deeper, it appears that the actual behavior of snapd matches systemd’s usage of the terms. Per the systemd.units man page:

Before=, After=
These two settings expect a space-separated list of unit names. They configure
ordering dependencies between units. If a unit foo.service contains a setting
Before=bar.service and both units are being started, bar.service’s start-up is delayed
until foo.service has finished starting up…

Because I would expect snapd to match systemd, it looks like the documentation needs to be updated, perhaps to

  • after
    An ordered list of applications the daemon is to be started after. Applications must be part of the same snap.
  • before
    An ordered list of applications the daemon is to be started before. Applications must be part of the same snap.

Thanks so much for reporting this in such detail, and I’m sorry for the confusion and the effort required. You’re absolutely right in that the documentation here is wrong - I’ve just looked into it too.

For future reference, the code is here:

I’ll update the doc - thank you!

The list of daemon types does not include “dbus”. Should it?

" oneshot Run once and exit after completion, although the process is still considered running."

That seems like a misleading description of a oneshot daemon – that even after it completes, it is still considered “running”. Would it not be a better description to say that, on its way out, a oneshot deamon notifies systemd of its completion, so that it is then considered “active”, and anyone waiting on it can now proceed?

It clearly is no longer “running”, but it is considered to have notified systemd that it is officially activated.

Thoughts?

1 Like

I see no mention of “reload-command”, should it not be here?

I’m confused about the relationship between “snap stop” on the command line, the “stop-command” value for a daemon, and the value of “stop-mode” (which, by the way, is not mentioned on this page, and probably should be).

“stop-command” is described as the “command from inside the snap to stop the service or daemon.” But does that mean that, if I run “snap stop” to stop a service, it maps to running that command inside the snap?

And how does the above relate to the specified value of “stop-mode”:

                "stop-mode": {
                    "type": "string",
                    "description": "controls how the daemon should be stopped",
                    "enum": [
                        "sigterm",
                        "sigterm-all",
                        "sighup",
                        "sighup-all",
                        "sigusr1",
                        "sigusr1-all",
                        "sigusr2",
                        "sigusr2-all"
                    ]
                },

It’s just not clear how all of the above ties together, and when you would use it.

Turns out the snapcraft schema description is wrong as well:

Are those description fields not backwards?

Absolutely. I’m not sure why we didn’t originally list this, but I’ve added it.

The optional stop-command when declared for a daemon specifies an executable that snapd runs before stopping the daemon (for example when stopping daemons as part of the snap’s refresh). The daemon is not stopped until the stop-command terminates. This can be used to gracefully handle a refresh by allowing the daemon to reach a stoppable state before it is actually stopped.

1 Like

Thanks for this. I’ve updated the description with your much more informative details.

With https://github.com/snapcore/snapd/pull/11855 landed we now also have: refresh-mode: ignore-running. Maybe something like:

  • refresh-mode Controls whether a daemon should be restarted during a snap refresh. Can be either restart, endure (to not restart) or ignore-running (ignore running services for the “refresh app awareness” feature). Defaults to restart.

Thanks for the update! I’ve edited the text to include ignore-running.

I’m not sure this is correct. If you look at the supported grammar here:

it does not seem like “ignore-running” is a valid value. More to the point, if you check the pull:

right at the top, it appears that the attribute of “ignore-running” is implicitly set by specifying:

“app-refresh-mode”: true

Am I reading this correctly? That is, ignore-running is not set directly, but is rather established indirectly by setting app-refresh-mode?

I just confirmed that ignore-running indeed is an invalid value for a daemon’s refresh-mode:

2022-09-26 16:05:44.063 Bad snapcraft.yaml content:
- unexpected value; permitted: 'endure', 'restart' (in field 'apps.portl-server.refresh-mode')

Thanks for looking into this. I’ve just tested it myself and get the same error. I suspect this is because Snapcraft does not yet support the keyword (as pointed out by @rpjday) but that snapd does (ie. it could be used snap.yaml, or maybe passed through from Snapcraft). I’ll check on its state and update the doc.