# Process supervision and management - Relevant schema: [[syndicate-rs]/syndicate-server/protocols/schemas/externalServices.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-rs/src/branch/main/syndicate-server/protocols/schemas/externalServices.prs) Assertions [requiring](../service.md#require-service) a service with name matching `DaemonService` cause the server to start a subprocess-based service: ```preserves-schema DaemonService = . ``` 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: ```preserves-schema DaemonProcess = . DaemonProcessSpec = / @simple CommandLine / @oneShot / @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: ```preserves-schema 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 `` 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.[^full-process-split-out] ```preserves-schema 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`](../service.md#service-states) 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. ```preserves-schema 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. ```preserves-schema 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`](../service.md#service-states) 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.) ```preserves-schema 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](../../protocol.md) relay. Standard error is logged. The subprocess is expected to make some [entity](../../glossary.md#entity) available to the server via [initial oid](../../glossary.md#initial-oid) 0. The server reflects this expectation by automatically placing a [service object](../service.md#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. ```preserves-schema 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. ```preserves-schema ProcessDir = / @present { dir: string } / @invalid { dir: any } / @absent {} . ``` ---- #### Notes [^full-process-split-out]: The `FullProcess` type is split out in order for it to be able to be reused outside the specific context of a *daemon* process.