book/operation/builtin/daemon
Process supervision and management
Assertions requiring a
service with name matching DaemonService cause the server
to start a subprocess-based service:
DaemonService = <daemon @id any> .
Each daemon service can have zero or more subprocesses
associated with it. Subprocesses can be long-lived services or
short-lived, system-state-changing programs or scripts.
Adding process specifications to a service
Each subprocess associated with a DaemonService is
defined with a DaemonProcess assertion:
DaemonProcess = <daemon @id any @config DaemonProcessSpec>.
DaemonProcessSpec =
/ @simple CommandLine
/ @oneShot <one-shot @setup CommandLine>
/ @full FullDaemonProcess .
The simplest kind of subprocess specification is a
CommandLine, either a string (sent to sh -c)
or an array of program name (looked up in the $PATH) and
arguments:
CommandLine = @shell string / @full FullCommandLine .
FullCommandLine = [@program string, @args string ...] .
The simple and oneShot variants of
DaemonProcessSpec expand into
FullDaemonProcess values as follows:
- a
simplecommand-line c becomes{ argv:c}; and - a record
<one-shotc>becomes{ argv:c, readyOnStart: false, restart: on-error }.
Subprocess specification
The FullDaemonProcess type matches a Preserves
dictionary having, at minimum, an argv key, and optionally
including many other parameters controlling various aspects of the
subprocess to be created.1
FullDaemonProcess =
& @process FullProcess
& @readyOnStart ReadyOnStart
& @restart RestartField
& @protocol ProtocolField .
FullProcess =
& { argv: CommandLine }
& @env ProcessEnv
& @dir ProcessDir
& @clearEnv ClearEnv .
The CommandLine associated with argv
specifies the program name to invoke and its command-line arguments. The
other options are described in the remainder of this section.
Ready-signalling
If the key readyOnStart is present in a
FullDaemonProcess dictionary, then if its associated value
is #t (the default), the service will be considered ready immediately
after it has been spawned; if its value is #f, some other
arrangement is expected to be made to announce a ready
ServiceState against the service’s name.
ReadyOnStart =
/ @present { readyOnStart: bool }
/ @invalid { readyOnStart: any }
/ @absent {} .
Whether and when to restart
The default restart policy is always. It can be
overridden by providing the key restart a
FullDaemonProcess dictionary, mapping to a valid
RestartPolicy value.
RestartField =
/ @present { restart: RestartPolicy }
/ @invalid { restart: any }
/ @absent {} .
RestartPolicy = =always / =on-error / =all / =never .
The valid restart policies are:
always: Whether the process terminates normally or abnormally, restart it without affecting any peer processes within the service.on-error: If the process terminates normally, leave everything alone; if it terminates abnormally, restart it without affecting peers.all: If the process terminates normally, leave everything alone; if it terminates abnormally, restart the whole daemon (all processes within theDaemonservice).never: Treat both normal and abnormal termination as normal termination; that is, never restart, and enter statecompleteeven if the process fails.
Speaking Syndicate Network Protocol via stdin/stdout
By default, the syndicate-server program assumes nothing
about the information to be read and written via a subprocess’s standard
input and standard output. This can be overridden with a
protocol entry in a FullDaemonProcess
specification. (Standard error is always considered to produce
information to be put in the system logs, however.)
ProtocolField =
/ @present { protocol: Protocol }
/ @invalid { protocol: any }
/ @absent {} .
Protocol = =none / =application/syndicate / =text/syndicate .
The available options for protocol are:
none: the standard input of the subprocess is connected to/dev/null, and the standard output and standard error are logged.application/syndicate: the subprocess standard input and output are used as a binary syntax Syndicate network protocol relay. Standard error is logged. The subprocess is expected to make some entity available to the server via initial oid 0. The server reflects this expectation by automatically placing a service object record into the dataspace alongside thedaemonrecord defining the subprocess.text/syndicate: as forapplication/syndicate, but Preserves’ text syntax is used instead of binary syntax.
Specifying subprocess environment variables
By default, the Unix process environment passed on to subprocesses is
not changed. Supplying clearEnv and/or env
keys alters this behaviour.
ClearEnv =
/ @present { clearEnv: bool }
/ @invalid { clearEnv: any }
/ @absent {} .
ProcessEnv =
/ @present { env: { EnvVariable: EnvValue ...:... } }
/ @invalid { env: any }
/ @absent {} .
EnvVariable = @string string / @symbol symbol / @invalid any .
EnvValue = @set string / @remove #f / @invalid any .
Setting clearEnv to #t causes the
environment to be emptied before env is processed and
before the subprocess is started. The env key is expected
to contain a dictionary whose keys are strings or symbols and whose
values are either a string, to set the variable to a new value, or
#f, to remove it from the environment.
Setting the Current Working Directory for a subprocess
By default, each subprocess inherits the current working directory of
the syndicate-server program. Setting a dir
key to a string value in a FullDaemonProcess overrides
this.
ProcessDir =
/ @present { dir: string }
/ @invalid { dir: any }
/ @absent {} .
Notes
Copyright © 2021–2023 Tony Garnock-Jones, CC BY 4.0
The
FullProcesstype is split out in order for it to be able to be reused outside the specific context of a daemon process.↩︎
