Documentation
¶
Overview ¶
Package process is the public facade for the SDK's keystone process-spawn primitive: it starts a child process under explicit credentials, in its own process group and session, and returns a handle that can wait for exit, signal the leader or its whole group, and stop the group gracefully with a SIGTERM→SIGKILL escalation.
It is a thin facade over internal/service/proc/exec. The public types are aliases of the internal/core/proc port, so a value built here is the same type the service layer consumes — no conversion, no parallel hierarchy.
Spec → systemd directive mapping ¶
Spec.Path / Args / Dir / Env ExecStart= / WorkingDirectory= / Environment= Spec.User / Group / Groups User= / Group= / SupplementaryGroups= Spec.Setpgid KillMode=control-group (group-killable tree) Spec.Setsid a new session, detached from the parent tty Spec.Nice Nice= Spec.OOMScoreAdj OOMScoreAdjust= Spec.Umask UMask= (applied via trampoline) Spec.Rlimits Limit*= (applied via trampoline)
Environment, and finding the executable ¶
A nil Spec.Env yields an empty environment — the child never silently inherits the supervisor's, so a spawned service starts from a known state. Pass an explicit slice (including os.Environ()) to inherit deliberately.
Spec.Path may be a bare name. "go" is searched in the PATH the CHILD will see — the PATH entry of Spec.Env whenever it names one, even empty, the parent's only when it names none — with os/exec's rules: the first executable in PATH order wins, and a match found only through a relative entry ("." or an empty one) is refused with exec.ErrDot, which the returned SpawnFailed wraps (errors.Is answers). A path with a separator is taken as written.
Standard streams ¶
Spec.Stdio selects how the child's stdin/stdout/stderr are wired: StdioInherit (the default) shares the parent's streams; StdioNull discards the child's output and gives it an immediate-EOF stdin; StdioCapture connects Spec.Stdout and Spec.Stderr (any io.Writer) and Spec.Stdin (any io.Reader), with a nil stream falling back to the null device for that one stream. In capture mode every byte the child writes reaches the writers before Wait returns, and the copier goroutines terminate at EOF (no leak). It composes with Setpgid/Setsid and credential drop. Stdin should be EOF-terminating.
Stopping a process group ¶
Stop sends the chosen signal to the entire process group, waits up to grace for exit, then escalates to SIGKILL on the group. Because the child leads its own group (Spec.Setpgid), forked grandchildren are reached too — no survivor is left behind.
Example ¶
spec := process.Spec{
Path: "/bin/sh",
Args: []string{"sh", "-c", "sleep 1000 & wait"},
Setpgid: true,
}
p, err := process.Start(context.Background(), spec)
if err != nil {
// err carries a central proc sentinel code (errs.HasCode).
return err
}
// Graceful stop: SIGTERM to the group, escalate to SIGKILL after 5s.
if err := p.Stop(context.Background(), 5*time.Second, process.SIGTERM); err != nil {
return err
}
exit, err := p.Wait()
_ = exit // exit.Code / exit.Signal / exit.UserTime / exit.MaxRSS
Resource limits and umask ¶
The Go runtime exposes no hook to run setrlimit(2) or umask(2) in the child between fork and exec, so Start honours Spec.Rlimits and Spec.Umask via a re-exec trampoline: when either is set, Start spawns this binary as a tiny self-trampoline that applies the limits in the fresh child, then execs the real target — so the target starts already under its limits, with no cgo and no dependency. An Rlimit naming a resource with no RLIMIT_* mapping on the platform (NPROC, MEMLOCK — absent from stdlib syscall) is still rejected up front with UnknownResource; a limit the kernel refuses to set (e.g. raising a hard cap unprivileged) fails the spawn rather than running the child unconfined. Nice and OOMScoreAdj are applied post-start on the live pid and surface a typed error if the host refuses.
Platforms ¶
Unix gets everything above. Windows spawns too, through CreateProcess: stdio wiring, Setpgid (a new console process group), Spec.Rlimits (enforced by a Job Object) and the PATH search (with PATHEXT) all work, while the fields with no Windows meaning at this layer — User/Group/Groups, Umask, Nice, OOMScoreAdj, ExtraFiles, CgroupPath — are refused with UnsupportedPlatform rather than dropped. There, SignalGroup reaches the leader only and Stop's escalation is TerminateProcess. Every other platform returns UnsupportedPlatform from Start; the package compiles everywhere.
The process itself ¶
Everything above acts on a child. Self and Build read the process they run in, on every platform, and never fail:
stats := process.Self()
stats.Goroutines, stats.HeapBytes, stats.GCPauses.Quantile(0.99), stats.CPUTime
build, ok := process.Build()
sdk, found := build.Module("github.com/kitsunium/sdk")
// sdk.Version is a release ("v0.4.6"), or "" with sdk.Revision/sdk.Time
// for a pseudo-version, or "" with sdk.Local for a directory.
CPUTime is the kernel's count (getrusage) where the platform has one and the Go runtime's estimate elsewhere — refreshed only at a garbage collection; Stats.CPUEstimated says which. The distributions and every counter are cumulative since the process started — subtract two snapshots for a window.
A module's recorded version conflates three things, and Module keeps them apart: a RELEASE in Version, a COMMIT in Revision and Time (a pseudo-version names one, and so does the main module's version-control stamp), and a DIRECTORY in Local and Dir (a replace, a workspace module). What is in a local directory NOW is a question for the framework's git.Head (ADR 0158).
Package process — the running process itself: what it was built from and what it is doing.
Package process — ergonomic re-exports: the handful of signal constants and resource sentinels callers need to drive Stop/SignalGroup and read typed errors without importing internal/core/proc directly.
Package process — StdioMode re-exports for wiring a child's standard streams.
Index ¶
Constants ¶
const ( // SIGTERM is the polite termination request — the default Stop signal. SIGTERM = Signal(syscall.SIGTERM) // SIGKILL is the unignorable kill Stop escalates to after the grace window. SIGKILL = Signal(syscall.SIGKILL) // SIGINT is the interrupt signal (Ctrl-C analogue). SIGINT = Signal(syscall.SIGINT) // SIGHUP is the hang-up / reload signal many daemons treat as "reconfigure". SIGHUP = Signal(syscall.SIGHUP) // SIGQUIT is the quit-with-core signal. SIGQUIT = Signal(syscall.SIGQUIT) )
The common control signals as typed process.Signal values, so callers pass process.SIGTERM to Stop/Signal without a syscall import. They equal any Signal parsed from the same name (the underlying value is the platform number).
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type BuildInfo ¶
type BuildInfo = svcself.BuildValue
BuildInfo is what the running binary was built from: the toolchain, the main package, the main module with its version-control stamp, and every dependency followed through its replacement. It is an alias of the service value.
func Build ¶
Build describes what the running binary was built from, and reports false when the binary carries no build information.
func ParseBuild ¶
ParseBuild describes a BuildInfo from elsewhere — one a test builds by hand, or debug.ParseBuildInfo's reading of another binary — exactly as Build describes the running one.
type Distribution ¶
type Distribution = svcself.DistributionValue
Distribution is one of the Go runtime's cumulative histograms, read as durations: Count, and Quantile(q) as the upper bound of the bucket that reaches q. It is an alias of the service value.
type ExitResult ¶
ExitResult is the outcome of a finished process — exit code, terminating signal, and resource usage. It is an alias of the core port's ExitValue.
type Limit ¶
type Limit = coreproc.LimitValue
Limit is a soft/hard resource-limit pair for setrlimit(2). It is an alias of the core port's LimitValue.
type Module ¶
type Module = svcself.ModuleValue
Module is one module of the running binary, with its release, its commit and its local directory told apart. It is an alias of the service value.
type Process ¶
Process is the handle to a spawned process: PID, Wait, Signal, SignalGroup, and a group-aware Stop. It is an alias of the core port interface.
func MustStart ¶
MustStart is like Start but panics with the typed error when the spawn fails — UnsupportedPlatform off Unix/Windows, InvalidSpec, RlimitFailed, … It is the idiomatic Go MustX opt-in (like regexp.MustCompile) for a consumer that chooses crash-on-failure at its own startup; the SDK itself never panics, and Start is the non-panicking form for normal use. The panic value is the typed error, so a top-level recover() can classify it via errs.CodeOf / HasCode.
func Start ¶
Start spawns the process described by spec and returns a live Process handle. It delegates to internal/service/proc/exec; ctx is honoured up to the fork/exec boundary. A bare Spec.Path is searched in the child's PATH (see the package documentation). On Windows the Unix-only Spec fields are refused with UnsupportedPlatform; on platforms that are neither Unix nor Windows, Start itself returns UnsupportedPlatform.
type Resource ¶
Resource identifies a per-process resource governed by setrlimit(2). It is an alias of the core port type.
const ( // ResourceNoFile limits the highest open file descriptor (RLIMIT_NOFILE). ResourceNoFile Resource = coreproc.ResourceNoFile // ResourceCore limits the size of a core dump in bytes (RLIMIT_CORE). ResourceCore Resource = coreproc.ResourceCore // ResourceCPU limits CPU time in seconds (RLIMIT_CPU). ResourceCPU Resource = coreproc.ResourceCPU // ResourceAS limits the process virtual address-space size (RLIMIT_AS). ResourceAS Resource = coreproc.ResourceAS )
The resource sentinels callers most often set in Spec.Rlimits, re-exported so a Spec can be built without importing internal/core/proc. The full set lives on the core Resource type.
type Signal ¶
Signal is a typed, platform-portable OS signal. It is an alias of the core port type, so process.SIGTERM and a signal parsed elsewhere compare equal.
type Spec ¶
Spec is the immutable description of a process to spawn — executable, environment, credentials, isolation topology, and scheduling attributes. It is an alias of the core port type.
type Stats ¶
type Stats = svcself.StatsValue
Stats is the running process at one instant: identity, scheduler settings, goroutines, heap, collections with their pause distribution, scheduling latency, and CPU time. Every count is cumulative since the process started. It is an alias of the service value.
type StdioMode ¶
StdioMode selects how a spawned child's standard streams (stdin, stdout, stderr) are wired. It is an alias of the core port type; set it on Spec.Stdio. The zero value is StdioInherit.
const StdioCapture StdioMode = coreproc.StdioCapture
StdioCapture connects the child to Spec.Stdout/Stderr (io.Writer) and Spec.Stdin (io.Reader); a nil stream falls back to the null device for that one stream. The systemd analogue is StandardOutput=/StandardError=/StandardInput=.
const StdioInherit StdioMode = coreproc.StdioInherit
StdioInherit shares the parent's stdin/stdout/stderr with the child — the default and the only behaviour before per-process wiring existed.