Documentation
¶
Overview ¶
Package subproc is the one place a child process gets its bound.
A short-lived child (git, gh, ssh, sops, tailscale, go tooling, ps) is started through Command: it runs under a context whose deadline is the caller's own when the caller has one sooner, and otherwise the named default of its kind (Kind.Budget), and it carries WaitDelay so that a killed child cannot hang its caller on a pipe. Without WaitDelay the kill is not enough: Output and CombinedOutput read until the pipe closes, and a grandchild (an ssh under git, a credential helper, a pager) that inherited the pipe holds it open after the child is gone.
A long-lived child (a harness run, a member's native child, a server) is started through Long: it runs under the caller's cancellable context and has no deadline, because how long it runs is not this package's call. WaitDelay is set there too, so the wait after its cancellation or exit is bounded, never the run itself.
Index ¶
- Constants
- func BoundFor(ctx context.Context, budget time.Duration) (context.Context, context.CancelFunc)
- func BudgetOf(name string, args []string) time.Duration
- func Command(ctx context.Context, k Kind, name string, args ...string) (*exec.Cmd, context.CancelFunc)
- func CommandFor(ctx context.Context, budget time.Duration, name string, args ...string) (*exec.Cmd, context.CancelFunc)
- func Context(ctx context.Context, name string, args ...string) *exec.Cmd
- func Expired(ctx context.Context) bool
- func GitBudgetFor(args []string) time.Duration
- func Long(ctx context.Context, name string, args ...string) *exec.Cmd
- type Bounded
- type Kind
- type TimeoutError
Constants ¶
const ( GitBudget = 60 * time.Second // GitLongBudget is a git that moves a whole repository or tree: clone, fetch, pull, // push, ls-remote (any network git), and a status, add, checkout, reset or clean of a // large worktree. GitLongBudget = 300 * time.Second GHBudget = 120 * time.Second SSHBudget = 300 * time.Second GoBudget = 300 * time.Second ToolBudget = 60 * time.Second )
Budgets by kind. A caller with its own context deadline sooner than the kind's budget keeps it; a caller that needs longer passes a context with no deadline to Long, or sets the option its own runner exposes.
const WaitDelay = 5 * time.Second
WaitDelay is how long a killed or exited child has to close its pipes before Wait closes them and returns.
Variables ¶
This section is empty.
Functions ¶
func BoundFor ¶
BoundFor narrows ctx to budget. A context that already ends sooner is kept as it is. A nil ctx is context.Background. The cancel function is always non-nil and is called when the child has been waited for.
func BudgetOf ¶
BudgetOf is the default budget of a program run by name with these arguments: its kind's, and for git the command line's (GitBudgetFor).
func Command ¶
func Command(ctx context.Context, k Kind, name string, args ...string) (*exec.Cmd, context.CancelFunc)
Command is exec.CommandContext under Bound(ctx, k) with WaitDelay set. The returned cancel is called when the child has been waited for (defer it).
func CommandFor ¶
func CommandFor(ctx context.Context, budget time.Duration, name string, args ...string) (*exec.Cmd, context.CancelFunc)
CommandFor is Command with an explicit budget.
func Context ¶
Context is exec.CommandContext under the caller's own context, unchanged, with WaitDelay set: for a caller whose context already carries the deadline it wants (a release build's budget, a probe's timeout) and only needs the pipe not to hang after the kill.
func GitBudgetFor ¶
GitBudgetFor is the budget of one git command line: GitLongBudget for a subcommand that goes to the network (clone, fetch, pull, push, ls-remote, submodule), GitBudget for the rest. Leading options are skipped, and one that takes a path or a config assignment as its value (-C dir, -c key=value, --git-dir dir, --work-tree dir, in the separated form; the equals form is a plain flag) consumes that value, so a repository path is never read as the subcommand.
Types ¶
type Bounded ¶
type Bounded struct {
Cmd *exec.Cmd
// Ctx is the bound context; Expired(Ctx) says the deadline ended the child.
Ctx context.Context
// Budget is the time the child was given, zero when the caller's own deadline was
// the sooner one, so a message never names a budget that did not apply.
Budget time.Duration
// Cancel is called once the child has been waited for.
Cancel context.CancelFunc
}
Bounded is one child built under a bound, not yet started.
type Kind ¶
type Kind int
Kind names the default budget of a short-lived child.
const ( // Git is git in any form: rev-parse, ls-tree, config, grep, show, diff. Git Kind = iota // GH is the GitHub CLI: one API round trip or a short listing. GH // SSH is ssh, scp and rsync: a connection, then a file or a short remote command. SSH // Go is go tooling run as a one-shot: env, list, tool. Go // Tool is every other one-shot: sops, age-keygen, tailscale, ps, lsof, sysctl, // diskutil, stty, taskkill and the sandbox's own check. Tool )
type TimeoutError ¶
type TimeoutError struct {
// What is the command line, for the message.
What string
// Budget is the time the child was given, when the caller knows it (zero otherwise).
Budget time.Duration
// Err is what the wait returned, usually "signal: killed".
Err error
}
TimeoutError is what a child killed at its deadline is reported as.
func (*TimeoutError) Error ¶
func (e *TimeoutError) Error() string
func (*TimeoutError) Unwrap ¶
func (e *TimeoutError) Unwrap() error