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 simple command-line c becomes { argv: c }; and
  • a record <one-shot c> 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.


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 the Daemonservice).

  • never: Treat both normal and abnormal termination as normal termination; that is, never restart, and enter state complete even 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 the daemon record defining the subprocess.

  • text/syndicate: as for application/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 {} .



The FullProcess type is split out in order for it to be able to be reused outside the specific context of a daemon process.