4.4 Service De- and Constructors

Each service has a start procedure and a stop procedure, also referred to as its constructor and destructor (see Services). The procedures listed below return procedures that may be used as service constructors and destructors. They are flexible enough to cover most use cases and carefully written to complete in a timely fashion.

Procedure: make-forkexec-constructor command [#:user #f] [#:group #f] [#:supplementary-groups ’()] [#:pid-file #f] [#:pid-file-timeout (default-pid-file-timeout)] [#:log-file #f] [#:directory (default-service-directory)] [#:file-creation-mask #f] [#:create-session? #t] [#:resource-limits ’()] [#:environment-variables (default-environment-variables)]

Return a procedure that forks a child process, closes all file descriptors except the standard output and standard error descriptors, sets the current directory to directory, sets the umask to file-creation-mask unless it is #f, changes the environment to environment-variables (using the environ procedure), sets the current user to user the current group to group unless they are #f and supplementary groups to supplementary-groups unless they are '(), and executes command (a list of strings.) When create-session? is true, the child process creates a new session with setsid and becomes its leader. The result of the procedure will be the <process> record representing the child process.

Note: This will not work as expected if the process “daemonizes” (forks); in that case, you will need to pass #:pid-file, as explained below.

When pid-file is true, it must be the name of a PID file associated with the process being launched; the return value is the PID once that file has been created. If pid-file does not show up in less than pid-file-timeout seconds, the service is considered as failing to start.

When log-file is true, it names the file to which the service’s standard output and standard error are redirected. log-file is created if it does not exist, otherwise it is appended to.

Note: See Log Rotation Service, for a service to rotate log files specified via the #:log-file parameter.

Guile’s setrlimit procedure is applied on the entries in resource-limits. For example, a valid value would be:

'((nproc 10 100)         ;number of processes
  (nofile 4096 4096))    ;number of open file descriptors
Procedure: make-kill-destructor [signal] [#:grace-period (default-process-termination-grace-period)]

Return a procedure that sends signal to the process group of the PID given as argument, where signal defaults to SIGTERM. If the process is still running after grace-period seconds, send it SIGKILL. The procedure returns once the process has terminated.

This does work together with respawning services, because in that case the stop method of the <service> arranges so that the service is not respawned.

The make-forkexec-constructor procedure builds upon the following procedures.

Procedure: exec-command command [#:user #f] [#:group #f] [#:supplementary-groups ’()] [#:log-file #f] [#:log-port #f] [#:input-port #f] [#:directory (default-service-directory)] [#:file-creation-mask #f] [#:create-session? #t] [#:resource-limits ’()] [#:environment-variables (default-environment-variables)]
Procedure: fork+exec-command command [#:user #f] [#:group #f] [#:supplementary-groups ’()] [#:log-file #f] [#:log-encoding "UTF-8"] [#:directory (default-service-directory)] [#:file-creation-mask #f] [#:create-session? #t] [#:resource-limits ’()] [#:environment-variables (default-environment-variables)]

Run command as the current process from directory, with file-creation-mask if it’s true, with rlimits, and with environment-variables (a list of strings like "PATH=/bin".) File descriptors 1 and 2 are kept as is or redirected to either log-port or log-file if it’s true, whereas file descriptor 0 (standard input) points to input-port or /dev/null; all other file descriptors are closed prior to yielding control to command. When create-session? is true, call setsid first (see setsid in GNU Guile Reference Manual).

By default, command is run as the current user. If the user keyword argument is present and not false, change to user immediately before invoking command. user may be a string, indicating a user name, or a number, indicating a user ID. Likewise, command will be run under the current group, unless the group keyword argument is present and not false, and supplementary-groups is not '().

fork+exec-command does the same as exec-command, but in a separate process whose PID it returns.

Variable: default-environment-variables

This parameter (see Parameters in GNU Guile Reference Manual) specifies the default list of environment variables to be defined when the procedures above create a new process.

It must be a list of strings where each string has the format name=value. It defaults to what environ returns when the program starts (see environ in GNU Guile Reference Manual).

Variable: default-pid-file-timeout

This parameter (see Parameters in GNU Guile Reference Manual) specifies the default PID file timeout in seconds, when #:pid-file is used (see above). It defaults to 5 seconds.

Variable: default-process-termination-grace-period

This parameter (see Parameters in GNU Guile Reference Manual) specifies the “grace period” (in seconds) after which a process that has been sent SIGTERM or some other signal to gracefully exit is sent SIGKILL for immediate termination. It defaults to 5 seconds.

Variable: default-respawn-delay

This parameter specifies the default value of the #:respawn-delay parameter of service (see Defining Services). It defaults to 0.1, meaning a 100ms delay before respawning a service.

Variable: default-respawn-limit

This parameter specifies the default value of the #:respawn-limit parameter of service (see Defining Services).

As an example, suppose you add this line to your configuration file:

(default-respawn-limit '(3 . 10))

The effect is that services will be respawned at most 3 times over a period of 10 seconds before being disabled.

One may also define services meant to be started on demand. In that case, shepherd listens for incoming connections on behalf of the program that handles them; when it accepts an incoming connection, it starts the program to handle them. The main benefit is that such services do not consume resources until they are actually used, and they do not slow down startup.

These services are implemented following the protocol of the venerable inetd “super server” (see inetd in GNU Inetutils). Many network daemons can be invoked in “inetd mode”; this is the case, for instance, of sshd, the secure shell server of the OpenSSH project. The Shepherd lets you define inetd-style services, specifically those in nowait mode where the daemon is passed the newly-accepted socket connection while shepherd is in charge of listening.

Listening endpoints for such services are described as records built using the endpoint procedure provided by the (shepherd endpoints) module:

Procedure: endpoint address [#:name "unknown"] [#:style SOCK_STREAM] [#:backlog 128] [#:socket-owner (getuid)] [#:socket-group (getgid)] [#:socket-directory-permissions #o755] [#:bind-attempts (default-bind-attempts)]

Return a new endpoint called name of address, an address as return by make-socket-address, with the given style and backlog.

When address is of type AF_INET6, the endpoint is IPv6-only. Thus, if you want a service available both on IPv4 and IPv6, you need two endpoints. For example, below is a list of endpoints to listen on port 4444 on all the network interfaces, both in IPv4 and IPv6 (“0.0.0.0” for IPv4 and “::0” for IPv6):

(list (endpoint (make-socket-address AF_INET INADDR_ANY 4444))
      (endpoint (make-socket-address AF_INET6 IN6ADDR_ANY 4444)))

This is the list you would pass to make-inetd-constructor or make-systemd-constructor—see below.

When address is of type AF_UNIX, socket-owner and socket-group are strings or integers that specify its ownership and that of its parent directory; socket-directory-permissions specifies the permissions for its parent directory.

Upon ‘EADDRINUSE’ (“Address already in use”), up to bind-attempts attempts will be made to bind on address, one every second.

Variable: default-bind-attempts

This parameter specifies the number of times, by default, that shepherd will try to bind an endpoint address if it happens to be already in use.

The inetd service constructor takes a command and a list of such endpoints:

Procedure: make-inetd-constructor command endpoints [#:service-name-stem _] [#:requirements ’()] [#:max-connections (default-inetd-max-connections)] [#:user #f] [#:group #f] [#:supplementary-groups ’()] [#:directory (default-service-directory)] [#:file-creation-mask #f] [#:create-session? #t] [#:resource-limits ’()] [#:environment-variables (default-environment-variables)]

Return a procedure that opens sockets listening to endpoints, a list of objects as returned by endpoint, and accepting connections in the background.

Upon a client connection, a transient service running command is spawned. Only up to max-connections simultaneous connections are accepted; when that threshold is reached, new connections are immediately closed.

The remaining arguments are as for make-forkexec-constructor.

Procedure: make-inetd-destructor

Return a procedure that terminates an inetd service.

The last type is systemd-style services. Like inetd-style services, those are started on demand when an incoming connection arrives, but using the protocol devised by the systemd service manager and referred to as socket activation. The main difference with inetd-style services is that shepherd hands over the listening socket(s) to the daemon; the daemon is then responsible for accepting incoming connections. A handful of environment variables are set in the daemon’s execution environment (see below), which usually checks them using the libsystemd or libelogind client library helper functions. The constructor and destructor for systemd-style daemons are described below.

Procedure: make-systemd-constructor command endpoints [#:lazy-start? #t] [#:user #f] [#:group #f] [#:supplementary-groups ’()] [#:log-file #f] [#:directory (default-service-directory)] [#:file-creation-mask #f] [#:create-session? #t] [#:resource-limits ’()] [#:environment-variables (default-environment-variables)]

Return a procedure that starts command, a program and list of argument, as a systemd-style service listening on endpoints, a list of <endpoint> objects.

command is started on demand on the first connection attempt on one of endpoints when lazy-start? is true; otherwise it is started as soon as possible. It is passed the listening sockets for endpoints in file descriptors 3 and above; as such, it is equivalent to an Accept=no systemd socket unit. The following environment variables are set in its environment:

LISTEN_PID

It is set to the PID of the newly spawned process.

LISTEN_FDS

It contains the number of sockets available starting from file descriptor 3—i.e., the length of endpoints.

LISTEN_FDNAMES

The colon-separated list of endpoint names.

This must be paired with make-systemd-destructor.

Procedure: make-systemd-destructor

Return a procedure that terminates a systemd-style service as created by make-systemd-constructor.

The following constructor/destructor pair is also available for your convenience, but we recommend using make-forkexec-constructor and make-kill-destructor instead (this is typically more robust than going through the shell):

Procedure: make-system-constructor command

The returned procedure will execute command in a shell and return #t if execution was successful, otherwise #f. For convenience, it takes multiple arguments which will be concatenated first.

Procedure: make-system-destructor command

Similar to make-system-constructor, but returns #f if execution of the command was successful, #t if not.

See Timers, for other service constructors and destructors: those for timers.