Documentation
¶
Overview ¶
Package detach runs a program that outlives the cockpit. The process is put into a session of its own and writes into files instead of pipes, so nothing it does depends on the server that started it: a restart, a self update or a crash leaves it running, and whoever comes next picks it up again.
What ties the two processes together is a lock file, not a process number. An exclusive flock is taken before anything starts and travels into the child as an inherited descriptor, so there is no moment where the program runs and the lock is free, and the lock dies with the last process that holds it. Whether that file can be locked is therefore whether the program still runs. No start times, no process table, the same code on every unix.
The program does not run directly: it runs under a hold process, a copy of this binary whose one job is to hold the lock, enforce the timeout and write down the exit code, because the exit code of a process this server did not start is lost to it (nobody can wait for a process that is not their child).
Index ¶
Constants ¶
This section is empty.
Variables ¶
var HoldArgs = []string{"run-detached"}
HoldArgs is the argv prefix that reaches Hold in the real binary. A test binary has no command tree in front of it and recognizes the same token itself, so the caller builds one argv and both binaries read it the same way.
Functions ¶
func Alive ¶
Alive reports whether a run this server did not start is still going. The lock is the truth. The wait is only hygiene: after a self update the runs of the previous image are this image's children, and a child nobody collects would sit around as a zombie for as long as this server lives. Not our child answers with an error, which is the normal case after a full restart and costs nothing.
func Hold ¶
Hold runs the program named in args and waits it out. It is the process behind `dev-cockpit run-detached`, and its job is to hold the run's lock, inherited as an open descriptor, for as long as the program runs: the program cannot drop it by closing its own descriptors, because this process keeps its copy. Standard output and error are already the files of the run, wired up by the server before this process started, and the program's exit code is returned as this process's own.
func Kill ¶
Kill ends the whole process group of a run. The lock is checked first: a run that already ended must not be signalled, its process number may belong to somebody else by now.
Types ¶
type Options ¶
type Options struct {
// Command is the program and its arguments, never a shell line. Whatever
// travels in here stays an argument and can never become a command.
Command []string
// Dir is the working directory of the program.
Dir string
// Env replaces the environment of the program when it is set; nil inherits
// this process's own.
Env []string
// Out is the file the program's standard output is written to. Err is the
// one for standard error; leaving it empty puts both into Out, which is
// what a caller asking for the combined output wants.
Out string
Err string
// Lock is the file whose exclusive lock says the run is still going.
Lock string
// Result is where the hold process writes the exit code. Leaving it empty
// means nobody asks about it, and the run reports through its output alone.
Result string
// Timeout bounds the run. It is enforced by the hold process, not by the
// caller: the server that asked for the run may be gone long before the
// run is, and a context here would die with it.
Timeout time.Duration
}
Options describe one detached run.
type Process ¶
type Process struct {
// contains filtered or unexported fields
}
Process is a started run: what it takes to find it again, and how to tell whether it is still going.
func Adopt ¶
Adopt is a run this server did not start, named by what an earlier one wrote down about it.
func Start ¶
Start launches one run detached from this server: its own session, its output straight into a file, no pipe between the two. That is what lets it keep running while the cockpit restarts, and it is why nothing here may hold a handle the child depends on.
func (Process) Kill ¶
func (p Process) Kill()
Kill ends the whole process group. A program spawns helpers, and killing only the leader would leave them writing into a file nobody reads.