You can start an OS process on any host in your cluster by creating a new process element at an anchor of your choosing that is a descendant of the host's server anchor. The created process element becomes your interface to the underlying OS process.
Suppose the variable anchor
holds an Anchor
object,
corresponding to a path in the anchor hierarchy that has no element attached to it.
For instance, say we obtained anchor
like this:
anchor := root.Walk([]string{"Xe2ac4c8c83976ce6", "job", "demo"})
This anchor corresponds to the path /Xe2ac4c8c83976ce6/job/demo
.
(Read more on navigating anchors here.)
To create a new process element and attach it to anchor
,
we use the anchor's MakeProc
method:
MakeProc(cmd Cmd) (Proc, error)
MakeProc
will start a new process on the host /Xe2ac4c8c83976ce6
,
as specified by the command parameter cmd
. If successful, it will create a
corresponding process element and attach it to the anchor. MakeProc
returns the
newly created process element (of type Proc
) as well as an
application error (of type error
), or it panics if a
system error occurs.
An application error can occur in one of two cases. Either the anchor already has another element attached to it, or the process execution was rejected by the host OS (due to a missing binary or insufficient permissions, for example).
MakeProc
never blocks.
The command parameter, of type Cmd
, specifies the standard POSIX-level execution
parameters and an additional parameter called Scrub
:
type Cmd struct { Env []string Dir string Path string Args []string Scrub bool }
If Scrub
is set, the process element will automatically be detached from the anchor
and discarded, as soon as the underlying OS process exits. If Scrub
is not set,
the process element will remain attached to the anchor even after the underlying OS process dies.
The latter regime is useful when one wants to start a job and return at a later time to check if
the job has already completed and what was its exit status. Furthermore, removing process elements
explicitly (rather than automatically) is a way of explicit accounting on the user's side. Thus
this regime is particularly well suited for applications that control circuit processes
programmatically (as opposed to manually).
Regardless of the setting of the Scrub
parameter, the user can
use the Scrub
method to discard the process element at any point:
Scrub()
A call to Scrub
will detach the process element from its anchor
and discard it, thereby freeing the anchor to attach other elements.
If the underlying OS process is still running, ‘scrubbing’ will not
terminate the process. (If OS process termination is desired, the user
must explicitly send a kill signal to the process, using a Signal
which is described later.)
For instance, the following code executes the GNU list command:
proc, err := a.MakeProc( cli.Cmd{ Env: []string{"TERM=xterm"}, Dir: "/", Path: "/bin/ls", Args: []string{"-l", "/"}, Scrub: true, }, )
The following picture tries to illustrate the relationship between the process element and the underlying OS process itself.
After its invocation, MakeProc
returns immediately,
while the underlying OS process is executing on the host machine.
After a successful execution the user is obligated, by the POSIX standard, to take care of the standard input, output and error streams of the underlying process. (For instance, if the standard input is not written to or closed, or if the output is not read from, some programs will pause in waiting.)
The standard streams of the executed process can be retrieved with the following methods of the process element:
Stdin() io.WriteCloser Stdout() io.ReadCloser Stderr() io.ReadCloser
It is allowed to close the standard output and error at any point into the stream. This will result in discarding all remaining data in the stream, without blocking the underlying process.
Eventually, the user is responsible for closing all standard streams otherwise the underlying process will block and not exit.
You can send a POSIX signal to the underlying process at any point (asynchronously) using:
Signal(sig string) error
The sig
string must be one of the following recognized
signal names:
ABRT
,
ALRM
,
BUS
,
CHLD
,
CONT
,
FPE
,
HUP
,
ILL
,
INT
,
IO
,
IOT
,
KILL
,
PIPE
,
PROF
,
QUIT
,
SEGV
,
STOP
,
SYS
,
TERM
,
TRAP
,
TSTP
,
TTIN
,
TTOU
,
URG
,
USR1
,
USR2
,
VTALRM
,
WINCH
,
XCPU
,
XFSZ
.
You can query the status of a process asynchronously, using:
Peek() ProcStat
The returned structure includes the command that started the process, a phase string describing the state of the
process and, in the event that the process has exited, an exit error value or nil
on successful exit.
type ProcStat struct { Cmd Cmd Exit error Phase string }
The phase string takes on one of the following values:
running
,
exited
,
stopped
,
signaled
,
continued
.
Finally, you can call Wait
asynchronously to block until the process ends:
Wait() (ProcStat, error)
If you call Wait
before the process has exited, the invocation will block
until exit occurs. Otherwise, it will return immediately. In both cases, a process status
structure (described earlier) is returned, which captures the exit state (successful or not) of the
underlying OS process.
Wait
can return an application error only in the event that it is interrupted
by a concurring call to Scrub
.