Describe builtin services
This commit is contained in:
parent
5a89f30613
commit
dd67e2950e
|
@ -1,7 +1,30 @@
|
||||||
# Configuration watcher
|
# Configuration watcher
|
||||||
|
|
||||||
- Any number of [**configuration watchers**](./config-watcher.md) may be created to monitor
|
- Relevant schema: [[syndicate-rs]/syndicate-server/protocols/schemas/internalServices.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-rs/src/branch/main/syndicate-server/protocols/schemas/internalServices.prs)
|
||||||
directories for changes to files written using the [server scripting
|
|
||||||
language](../scripting.md). (These can also be started from the `syndicate-server`
|
|
||||||
command-line with `-c` options.)
|
|
||||||
|
|
||||||
|
Assertions [requiring](../service.md#require-service) a service with name matching
|
||||||
|
`ConfigWatcher` cause the server to start a configuration watcher service monitoring files in
|
||||||
|
and subdirectories of the given `path` for changes:
|
||||||
|
|
||||||
|
```preserves-schema
|
||||||
|
ConfigWatcher = <config-watcher @path string @env ConfigEnv>.
|
||||||
|
ConfigEnv = { symbol: any ...:... }.
|
||||||
|
```
|
||||||
|
|
||||||
|
The `path` may name either a file or directory. Any time the configuration watcher finds a file
|
||||||
|
matching the glob `*.pr` within the tree rooted at `path`, it loads the file. Each time a
|
||||||
|
`*.pr` file is loaded, it is interpreted as a [configuration scripting
|
||||||
|
language](../scripting.md) program, with a copy of `env` as the "initial environment" for the
|
||||||
|
script.
|
||||||
|
|
||||||
|
Whenever a change to a `*.pr` file is detected, the configuration watcher reloads the file,
|
||||||
|
discarding previous internal state related to the file.
|
||||||
|
|
||||||
|
Note that a quirk of the config language requires that there exist an entry in `env` with key
|
||||||
|
the symbol `config` and value an [entity reference](../../glossary.md#reference) (usually
|
||||||
|
denoting a [dataspace entity](../../glossary.md#dataspace)). However, the `config` entry need
|
||||||
|
not be the same as the surrounding `$config`! A useful pattern is to set up a new
|
||||||
|
`ConfigWatcher` with `env` containing a `config` binding pointing to an
|
||||||
|
[attenuated](../../glossary.md#attenuation) reference to the current `config` dataspace, or
|
||||||
|
even [an entirely fresh dataspace](../scripting.md#expr:dataspace) created specifically for the
|
||||||
|
task.
|
||||||
|
|
|
@ -1,4 +1,181 @@
|
||||||
# Process supervision and management
|
# Process supervision and management
|
||||||
|
|
||||||
- Finally, [**external programs**](./daemon.md) can be started, either as long-lived "daemon"
|
- 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)
|
||||||
services or as one-off scripts.
|
|
||||||
|
Assertions [requiring](../service.md#require-service) a service with name matching
|
||||||
|
`DaemonService` cause the server to start a subprocess-based service:
|
||||||
|
|
||||||
|
```preserves-schema
|
||||||
|
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:
|
||||||
|
|
||||||
|
```preserves-schema
|
||||||
|
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:
|
||||||
|
|
||||||
|
```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 `<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.[^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.
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
# Gatekeeper
|
# Gatekeeper
|
||||||
|
|
||||||
- Relevant schema:
|
|
||||||
- Gatekeepers: [[syndicate-protocol]/schemas/gatekeeper.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/gatekeeper.prs)
|
|
||||||
- Sturdyrefs: [[syndicate-protocol]/schemas/sturdy.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/sturdy.prs)
|
|
||||||
|
|
||||||
When `syndicate-server` starts, it creates a *gatekeeper service entity*, which accepts
|
When `syndicate-server` starts, it creates a *gatekeeper service entity*, which accepts
|
||||||
`resolve` assertions requesting conversion of a long-lived "sturdyref" to a [live
|
`resolve` assertions requesting conversion of a long-lived "sturdyref" to a [live
|
||||||
reference](../../glossary.md#reference). The gatekeeper is the [default
|
reference](../../glossary.md#reference). The gatekeeper is the [default
|
||||||
object](../../glossary.md#initial-ref), available as [OID](../../glossary.md#oid) 0 to peers at
|
object](../../glossary.md#initial-ref), available as [OID](../../glossary.md#oid) 0 to peers at
|
||||||
the other end of [relay listener](./relay-listener.md) connections.
|
the other end of [relay listener](./relay-listener.md) connections.
|
||||||
|
|
||||||
|
## Gatekeeper protocol
|
||||||
|
|
||||||
|
- Relevant schema: [[syndicate-protocol]/schemas/gatekeeper.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/gatekeeper.prs)
|
||||||
|
|
||||||
```preserves-schema
|
```preserves-schema
|
||||||
Resolve = <resolve @sturdyref sturdy.SturdyRef @observer #!#!any>.
|
Resolve = <resolve @sturdyref sturdy.SturdyRef @observer #!#!any>.
|
||||||
```
|
```
|
||||||
|
@ -27,6 +27,8 @@ asserted to the `observer` in the `resolve`.
|
||||||
|
|
||||||
## Sturdyrefs
|
## Sturdyrefs
|
||||||
|
|
||||||
|
- Relevant schema: [[syndicate-protocol]/schemas/sturdy.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/sturdy.prs)
|
||||||
|
|
||||||
A "sturdyref" is a long-lived certificate including a cryptographic signature that can be
|
A "sturdyref" is a long-lived certificate including a cryptographic signature that can be
|
||||||
upgraded by a gatekeeper entity to a live reference to the entity named in the sturdyref. The
|
upgraded by a gatekeeper entity to a live reference to the entity named in the sturdyref. The
|
||||||
current sturdyref implementation is based on the design of
|
current sturdyref implementation is based on the design of
|
||||||
|
@ -65,9 +67,8 @@ is shamelessly taken from [macaroons][], though our caveats presently embody onl
|
||||||
Macaroons paper are called "first-party caveats" over assertion structure; future versions of
|
Macaroons paper are called "first-party caveats" over assertion structure; future versions of
|
||||||
the server may add "third-party caveats" and other, richer, predicates over assertions.
|
the server may add "third-party caveats" and other, richer, predicates over assertions.
|
||||||
|
|
||||||
Each `Attenuation`'s `Caveat`s are run in *right to left* order.
|
Each `Attenuation`'s `Caveat`s are run in *right to left* order. The structure and
|
||||||
|
interpretation of `Caveat`s is described fully in [the relevant section of the Syndicate
|
||||||
For details of the structure and interpretation of `Caveat`s, see [the relevant section of the
|
network protocol specification](../../protocol.md#attenuation-of-authority).
|
||||||
Syndicate network protocol specification](../../protocol.md#attenuation-of-authority).
|
|
||||||
|
|
||||||
[Macaroons]: ../../glossary.md#macaroon
|
[Macaroons]: ../../glossary.md#macaroon
|
||||||
|
|
|
@ -1 +1,23 @@
|
||||||
# Logging
|
# Logging
|
||||||
|
|
||||||
|
The Synit logging infrastructure is still underdeveloped.
|
||||||
|
|
||||||
|
At present, there is an actor created at `syndicate-server` startup time that monitors the
|
||||||
|
`$log` dataspace for messages of the form:
|
||||||
|
|
||||||
|
```preserves-schema
|
||||||
|
LogEntry = <log @timestamp string @detail { any: any ...:... }> .
|
||||||
|
```
|
||||||
|
|
||||||
|
When it receives a log entry, it looks for a few conventional and optional keys in the `detail`
|
||||||
|
field, each permitted to be any kind of [value](../../glossary.md#value):
|
||||||
|
|
||||||
|
- `pid`, conventionally a Unix process ID;
|
||||||
|
- `line`, conventionally a string of free-form text intended for people to read;
|
||||||
|
- `service`, conventionally a service name in the sense of
|
||||||
|
[`require-service`](../service.md#require-service)/[`run-service`](../service.md#run-service); and
|
||||||
|
- `stream`, conventionally one of the symbols `stdout` or `stderr`.
|
||||||
|
|
||||||
|
The timestamp and the special keys are then formatted, along with all other information in the
|
||||||
|
entry record, and printed to the `syndicate-server`'s standard error at `INFO` level using
|
||||||
|
[`tracing`](https://docs.rs/tracing/latest/tracing/).
|
||||||
|
|
|
@ -1,11 +1,61 @@
|
||||||
# TCP/IP, WebSocket and Unix-socket Transports
|
# Relay Listeners
|
||||||
|
|
||||||
- Any number of [**TCP/IP, WebSocket, and Unix socket transports**](./relay-listener.md) may
|
- Relevant schema:
|
||||||
be configured to allow external access to the gatekeeper and its registered services. (These
|
- [[syndicate-rs]/syndicate-server/protocols/schemas/internalServices.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-rs/src/branch/main/syndicate-server/protocols/schemas/internalServices.prs)
|
||||||
can also be started from the `syndicate-server` command-line with `-p` and `-s` options.)
|
- [[syndicate-protocol]/schemas/transportAddress.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/transportAddress.prs)
|
||||||
|
|
||||||
## TCP/IP
|
The `syndicate-server` program can be configured to listen on TCP/IP ports and Unix
|
||||||
|
sockets[^sock-stream-only] for incoming connections speaking the [Syndicate network
|
||||||
|
protocol][protocol].
|
||||||
|
|
||||||
## WebSockets
|
[protocol]: ../../protocol.md
|
||||||
|
|
||||||
|
## <span id="tcpip"></span>TCP/IP and WebSockets
|
||||||
|
|
||||||
|
Assertions [requiring](../service.md#require-service) a service with name matching
|
||||||
|
`TcpRelayListener` cause the server to start a TCP server socket on the given `addr`'s `host`
|
||||||
|
and `port`, exposing the `gatekeeper` [entity reference](../../glossary.md#reference) as the
|
||||||
|
[initial ref](../../glossary.md#initial-ref) of incoming connections:
|
||||||
|
|
||||||
|
```preserves-schema
|
||||||
|
TcpRelayListener = <relay-listener @addr Tcp @gatekeeper #!gatekeeper.Resolve> .
|
||||||
|
Tcp = <tcp @host string @port int>.
|
||||||
|
```
|
||||||
|
|
||||||
|
When a new connection arrives, the first byte is examined to see what kind of connection it is
|
||||||
|
and which Preserves syntax it will use.
|
||||||
|
|
||||||
|
- If it is ASCII "`G`" (0x47), it cannot be the start of a [protocol][] packet, so it is
|
||||||
|
interpreted as the start of a WebSocket connection and handed off to the
|
||||||
|
[tokio_tungstenite](https://docs.rs/tokio-tungstenite/latest/tokio_tungstenite/) WebSocket
|
||||||
|
library. Within the WebSocket's context, each packet must be encoded as a binary packet
|
||||||
|
using Preserves binary syntax.
|
||||||
|
|
||||||
|
- Otherwise, if it could start a valid UTF-8 sequence, the connection will be a plain TCP/IP
|
||||||
|
link using the Preserves text syntax.
|
||||||
|
|
||||||
|
- Otherwise, it's a byte which cannot be part of a valid UTF-8 sequence, so it is interpreted
|
||||||
|
as a Preserves binary syntax tag: the connection will be a plain TCP/IP link using Preserves
|
||||||
|
binary syntax.
|
||||||
|
|
||||||
## Unix sockets
|
## Unix sockets
|
||||||
|
|
||||||
|
Assertions [requiring](../service.md#require-service) a service with name matching
|
||||||
|
`UnixRelayListener` cause the server to start a Unix server socket on the given `addr`'s
|
||||||
|
`path`, exposing the `gatekeeper` [entity reference](../../glossary.md#reference) as the
|
||||||
|
[initial ref](../../glossary.md#initial-ref) of incoming connections:
|
||||||
|
|
||||||
|
```preserves-schema
|
||||||
|
UnixRelayListener = <relay-listener @addr Unix @gatekeeper #!gatekeeper.Resolve> .
|
||||||
|
Unix = <unix @path string>.
|
||||||
|
```
|
||||||
|
|
||||||
|
Syntax autodetection is as for [TCP/IP](#tcpip), except that WebSockets are not supported over
|
||||||
|
Unix sockets.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
#### Notes
|
||||||
|
|
||||||
|
[^sock-stream-only]: Only `SOCK_STREAM` Unix sockets are supported, at present. In future,
|
||||||
|
`SOCK_DGRAM` could be useful for e.g. file-descriptor passing.
|
||||||
|
|
|
@ -194,7 +194,8 @@ are introduced into the environment.
|
||||||
The right-hand-side of a `let`, after the equals sign, is either a normal *ValueExpr* or one of
|
The right-hand-side of a `let`, after the equals sign, is either a normal *ValueExpr* or one of
|
||||||
the following special "convenience" expressions:
|
the following special "convenience" expressions:
|
||||||
|
|
||||||
- `dataspace`: Evaluates to a fresh, empty [dataspace](../glossary.md#dataspace) entity.
|
- <span id="expr:dataspace">`dataspace`: Evaluates to a fresh, empty
|
||||||
|
[dataspace](../glossary.md#dataspace) entity.</span>
|
||||||
|
|
||||||
- `timestamp`: Evaluates to a string containing an
|
- `timestamp`: Evaluates to a string containing an
|
||||||
[RFC-3339](https://datatracker.ietf.org/doc/html/rfc3339)-formatted timestamp.
|
[RFC-3339](https://datatracker.ietf.org/doc/html/rfc3339)-formatted timestamp.
|
||||||
|
|
|
@ -46,7 +46,7 @@ without use of variables or any reactive constructs.
|
||||||
A few different kinds of assertions, all declared in [the `service.prs` schema][service.prs],
|
A few different kinds of assertions, all declared in [the `service.prs` schema][service.prs],
|
||||||
form the heart of the system.
|
form the heart of the system.
|
||||||
|
|
||||||
### Assert that a service and its dependencies should be started
|
### <span id="require-service"></span>Assert that a service and its dependencies should be started
|
||||||
|
|
||||||
```preserves-schema
|
```preserves-schema
|
||||||
RequireService = <require-service @serviceName any>.
|
RequireService = <require-service @serviceName any>.
|
||||||
|
@ -55,7 +55,7 @@ RequireService = <require-service @serviceName any>.
|
||||||
Asserts that a service should begin (and stay) running after waiting for its dependencies and
|
Asserts that a service should begin (and stay) running after waiting for its dependencies and
|
||||||
considering reverse-dependencies, blocks, and so on.
|
considering reverse-dependencies, blocks, and so on.
|
||||||
|
|
||||||
### Assert that a service should start *right now*
|
### <span id="run-service"></span>Assert that a service should start *right now*
|
||||||
|
|
||||||
```preserves-schema
|
```preserves-schema
|
||||||
RunService = <run-service @serviceName any>.
|
RunService = <run-service @serviceName any>.
|
||||||
|
@ -76,7 +76,7 @@ ServiceDependency = <depends-on @depender any @dependee ServiceState>.
|
||||||
Asserts that, when `depender` is `require-service`d, it should not be started until `dependee`
|
Asserts that, when `depender` is `require-service`d, it should not be started until `dependee`
|
||||||
has been asserted, and also that `dependee`'s `serviceName` should be `require-service`d.
|
has been asserted, and also that `dependee`'s `serviceName` should be `require-service`d.
|
||||||
|
|
||||||
### Convey the current state of a service
|
### <span id="service-states"></span>Convey the current state of a service
|
||||||
|
|
||||||
```preserves-schema
|
```preserves-schema
|
||||||
ServiceState = <service-state @serviceName any @state State>.
|
ServiceState = <service-state @serviceName any @state State>.
|
||||||
|
@ -101,7 +101,7 @@ A few built-in states are defined:
|
||||||
|
|
||||||
In addition, any user-defined value is acceptable as a `State`.
|
In addition, any user-defined value is acceptable as a `State`.
|
||||||
|
|
||||||
### Make an entity representing a service instance available
|
### <span id="service-object"></span>Make an entity representing a service instance available
|
||||||
|
|
||||||
```preserves-schema
|
```preserves-schema
|
||||||
ServiceObject = <service-object @serviceName any @object any>.
|
ServiceObject = <service-object @serviceName any @object any>.
|
||||||
|
|
Loading…
Reference in New Issue