supervisor

package
v0.2.46 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 5, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package supervisor runs one long-lived child process for a supervised harness runner and keeps it running.

The child is always the agent's OWN executable invoked with a different subcommand (`railgrid runner run ...`), so a runner upgrades with the agent and there is no second artifact to distribute or verify.

Three properties are load-bearing and are enforced here rather than left to callers:

  • The child never runs as uid 0. A root agent MUST hand over an explicit non-root uid/gid; a non-root agent runs the child as itself. There is no third case.
  • The child's environment is built from scratch. Nothing is inherited, so the hub bearer token, the agent kubeconfig path and any API keys in the agent's environment cannot reach a code-execution child. This is the same reasoning as the Codex adapter's safeEnv, taken one step further: safeEnv subtracts from os.Environ(), this adds to an empty slice.
  • Stop kills the whole process GROUP. The runner spawns Codex, which spawns git; signalling only the direct child would leave those behind.

Index

Constants

View Source
const (
	// DefaultInitialBackoff is the pause after the first unexpected exit.
	DefaultInitialBackoff = time.Second
	// MaxBackoff caps the restart pause. A wedged runner must keep retrying —
	// the host may recover — but not faster than once a minute.
	MaxBackoff = 60 * time.Second
	// DefaultStopGrace is how long a child gets to exit after SIGTERM before
	// the group is killed.
	DefaultStopGrace = 10 * time.Second
	// DefaultMaxLogBytes bounds the runner log file. A runner that crash-loops
	// while printing must not fill the host's disk.
	DefaultMaxLogBytes int64 = 8 << 20
)
View Source
const DefaultPath = "/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin"

DefaultPath is the search path handed to runner children. It matches the LaunchDaemon plist so a Homebrew-installed Codex is found on macOS.

View Source
const InheritUID = -1

InheritUID tells the supervisor to run the child as the agent's own account. It is only legal when the agent itself is not root.

Variables

This section is empty.

Functions

func ChildEnv

func ChildEnv(home, path string) []string

ChildEnv builds a child environment from scratch. It deliberately takes only what a process needs to find its home and its tools — never os.Environ().

func ReclaimStaleHolder

func ReclaimStaleHolder(lockPath string, grace time.Duration) (int, error)

ReclaimStaleHolder terminates the process that holds lockPath when that lock belongs to a child of an agent that no longer exists.

The lock is a flock whose content is the holder's pid, written by the child that acquired it. A child outlives its agent when the agent is killed rather than stopped (macOS has no parent-death signal), and it then keeps the lock and the listening port: the new agent's own child can never start, while the orphan keeps answering the port with a stale build and configuration. This is only called before the first child of an agent process is started, so anything holding the lock at that point is such an orphan; a lock taken while the agent runs is never touched here.

It returns the pid it terminated, or 0 when the lock was free.

Types

type Config

type Config struct {
	// Name identifies the child in log lines and errors.
	Name string
	// Executable is an absolute path. Callers pass os.Executable().
	Executable string
	// Args are the arguments after the executable name.
	Args []string
	// Dir is the child's working directory.
	Dir string
	// Env is the COMPLETE environment for the child. Nothing is added and
	// nothing is inherited; build it with ChildEnv.
	Env []string
	// UID/GID are the account the child runs as, or InheritUID to run as the
	// agent's own (non-root) account.
	UID int
	GID int
	// LogPath receives the child's stdout and stderr, owner-only and bounded.
	LogPath string
	// MaxLogBytes bounds LogPath; zero means DefaultMaxLogBytes.
	MaxLogBytes int64
	// StopGrace is the SIGTERM-to-SIGKILL window; zero means DefaultStopGrace.
	StopGrace time.Duration
	// InitialBackoff is the first restart pause; zero means
	// DefaultInitialBackoff. Tests shorten it.
	InitialBackoff time.Duration
}

Config describes one supervised child.

type Supervisor

type Supervisor struct {
	// contains filtered or unexported fields
}

Supervisor owns at most one running child at a time.

func New

func New(cfg Config) (*Supervisor, error)

New validates cfg and returns a stopped supervisor. It refuses a uid-0 target outright: a code-execution child of a root agent must drop privileges, and "the caller forgot" must fail here rather than at exec time.

func (*Supervisor) Alive

func (s *Supervisor) Alive() bool

Alive reports whether a child process is currently running.

func (*Supervisor) LastError

func (s *Supervisor) LastError() error

LastError is the most recent unexpected child exit or launch failure, or nil.

func (*Supervisor) Start

func (s *Supervisor) Start(ctx context.Context)

Start launches the child and keeps restarting it until Stop. Calling Start on an already-running supervisor is a no-op, so a reconcile loop can call it on every pass.

func (*Supervisor) Starts

func (s *Supervisor) Starts() int

Starts is the number of child launches so far. Tests use it to observe restarts; the harness plane uses it only for log lines.

func (*Supervisor) Stop

func (s *Supervisor) Stop(ctx context.Context) error

Stop terminates the child's process group and waits for the supervision loop to finish. It is safe to call on a stopped supervisor.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL