8.6 What a Caller Sees

Operations are how a caller observes something taking effect. This article covers what the model looks like from the outside; the wire contract itself is PSPU §4.

8.6.1 Every lifecycle command returns an identifier #

A command that creates, merges into, queues, cancels, clears or executes an operation returns that operation's identifier. A caller can then poll it, or block on it.

Two cases return no identifier, because no operation exists: a command whose target is already in the state it asks for, and one that has no effect at all — a stop on an Inactive service. Both return the service's status instead of an acknowledgement, which is the honest answer, and which also says what else the caller may do to the service (§10.2).

Commands that never create an operation — status, list, operation-status — have their own shapes. So do the three job commands, which never create an operation either: a submitted job has no state machine to contend for, so job-stop acts on it directly and answers with the job view.

8.6.2 Waiting #

Lifecycle commands block by default until the operation is terminal. The exception is reload, which returns immediately unless asked otherwise, because a reload's outcome is often advisory and a caller usually wants the identifier rather than the wait.

A waiting connection is not idle and is never closed by the idle timeout, however long the operation runs. It is bounded by the operation's own lifetime instead.

8.6.3 Merging is invisible #

A caller whose command merged receives the surviving operation's identifier and blocks on that operation's outcome. Nothing tells them they merged, because there is nothing they could usefully do about it. The consequence worth knowing is that the identifier a caller gets back may be older than their request, and its created_at will be earlier than when they sent it — which is exactly right, because that is when the work they are waiting on actually began.

8.6.4 What an operation's result carries #

A completed stop or reset carries the resulting service state; a completed start carries the readiness that satisfied it — alive readiness: process started, notify readiness: READY=1, or the exit code for a Oneshot — rather than a state name. A failed one carries the failure reason; one that peinit could not execute (§8.2) carries internal_error: <cause>. A merged one carries the survivor's identifier. A cancelled or aborted one carries why.

For a reload, the result also determines the reload's mode — whether the service confirmed the reload with a READY=1, whether peinit is merely assuming it happened, or whether it outright failed.

8.6.5 The job view #

A submitted job is reported in one shape on both sockets, the job view of PSPU §7.7: identifier, type of submitted, state, cause, submitter and identity SIDs, logon session, description, image path, pid while there is a process, ready for a notify job, exit code or signal, the retained status_text and progress, and the three timestamps. Every inapplicable field is present and null, and pid is null once the job is terminal — there is no process to name. Abandoned is the exception, and the reason for it: an abandoned job's processes survived SIGKILL and are still running, so its pid is kept.

What a submitter sees of its job on the jobs socket is exactly what an administrator sees of it in job-status, but for one field the control socket adds: granted, the job rights that caller holds on it (§10.2). And job-list is a list of the same views, filtered by JOB_QUERY on each (§10.2). A job-stop with wait registers a wait on the connection like a lifecycle command's, answered with the terminal view — or UNKNOWN_JOB, if the record was purged before the answer could be sent.

Edit this page