runner

package
v0.9.1 Latest Latest
Warning

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

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

Documentation

Overview

Package runner is podium-runner: PID 1 of every Podium task container.

It runs the task command as a child in its own process group, forwards signals to that group, reaps orphaned grandchildren, and reports structured events to the node over a Unix socket. Being PID 1 is the whole point: the kernel discards a default-disposition signal sent to a PID namespace's init, so a task command running as PID 1 itself cannot be asked to stop — only killed. The runner has a real handler, so `podium task cancel` becomes a prompt SIGTERM instead of a 30-second wait for SIGKILL.

This package depends on nothing outside the standard library. The binary is bind-mounted read-only into images Podium does not control.

Index

Constants

View Source
const (
	EnvTaskID     = "PODIUM_TASK_ID"
	EnvLeaseID    = "PODIUM_LEASE_ID"
	EnvEventsSock = "PODIUM_EVENTS_SOCK"
	EnvWorkDir    = "PODIUM_WORKDIR"
	EnvKillAfter  = "PODIUM_KILL_AFTER"
	// EnvHold is set on a task that exposes ports: when its command exits, the runner
	// reports the exit and stays up, so whatever the command left running keeps serving.
	EnvHold = "PODIUM_HOLD"
)

Environment variables the node sets on the task container.

View Source
const (
	DefaultEventsSock = "/podium/events.sock"
	DefaultWorkDir    = "/workspace"

	// DefaultKillAfter is how long a child gets between the SIGTERM we forward and the
	// SIGKILL we send its group. It stays inside the node's own 30s cancel grace so the
	// container is already gone when the engine's SIGKILL would land.
	DefaultKillAfter = 25 * time.Second

	// DefaultDialTimeout is how long the event socket is retried before giving up.
	// Events are best-effort: the command runs either way.
	DefaultDialTimeout = 5 * time.Second
)

Defaults for the values above and for the timers this package owns.

View Source
const ArtifactsDir = "/workspace/.podium/artifacts"

ArtifactsDir is where a task drops files it wants kept without asking for anything: the node collects everything under it when the task exits. It is inside the workspace volume so a sidecar or a later step can write there too.

View Source
const HoldDir = "/podium/hold"

HoldDir is a tmpfs the node mounts on a held task. The runner writes the command's exit there, because a node that restarted while the command ran has lost the event socket and can only learn the exit by reading this file.

View Source
const HoldExitFile = HoldDir + "/exit"

HoldExitFile is the file under HoldDir that holds the exit, as the exited event's JSON.

View Source
const MaxMessageBytes = 32 << 10

MaxMessageBytes caps `text`. The node's line scanner allows 64 KiB per line (maxRunnerLine); half of that leaves room for the envelope, attachments and JSON escaping.

View Source
const MessageTypeFinal = "final"

MessageTypeFinal is what a message is when the task does not say otherwise: the answer.

Variables

This section is empty.

Functions

func AddArtifact

func AddArtifact(cfg Config, args []string) int

AddArtifact is `podium-runner artifact add PATH [--name NAME] [--type CONTENT_TYPE]`.

It writes one line to the node's event socket and exits. It is deliberately a separate invocation of the same binary rather than an API: a task can call it from any shell, in the middle of a run, with no library and no credentials — the socket is already mounted and the node is the only thing listening on it.

func AddMessage

func AddMessage(cfg Config, args []string, stdin io.Reader) int

AddMessage is `podium-runner message [--type progress|final] [--attach NAME]... TEXT`. TEXT of "-" reads the message from stdin.

Like `artifact add` it is a separate invocation of the same binary rather than an API: a task says what it has to say from any shell, with no library and no credentials.

func Gateway added in v0.6.0

func Gateway(args []string) int

Gateway is `podium-runner gateway`: the container a node puts on an exposed task's network. It listens on every exposed port and forwards each connection to the sidecar or the task container that owns it, by name, which is what lets a node publish a task's ports on one address whatever its platform can route to.

func Run

func Run(ctx context.Context, cfg Config, argv []string) int

Run executes argv to completion and returns the exit code the runner should exit with: the child's own code, or 128+signo when a signal killed it. It never calls os.Exit, so it is testable.

func ServeGateway added in v0.6.0

func ServeGateway(ctx context.Context, host string, routes []Route) error

ServeGateway forwards until ctx ends. host is the listen address, empty for every one.

func Splice added in v0.6.0

func Splice(c net.Conn, dial func() (net.Conn, error))

Splice connects c to what dial returns and copies both ways until both sides are done, passing a half-close along so a request/response protocol still sees its EOF.

Types

type Config

type Config struct {
	TaskID  string
	LeaseID string
	// EventsSock is the Unix socket the node listens on; empty means DefaultEventsSock.
	EventsSock string
	// WorkDir is the child's working directory.
	WorkDir string
	// KillAfter is the SIGTERM → SIGKILL delay for the child's process group.
	KillAfter time.Duration
	// DialTimeout bounds the retry window for the event socket.
	DialTimeout time.Duration
	// Hold keeps the runner up after the command exits, until it is asked to stop.
	Hold bool
	// HoldExitFile is where a held exit is also written; empty means HoldExitFile.
	HoldExitFile string
	// Stdout and Stderr are the files the child inherits as fd 1 and fd 2, and Stderr is
	// also where the runner writes its own diagnostics. Both default to the process's.
	// Stdin is always inherited.
	Stdout *os.File
	Stderr *os.File
}

Config is everything the runner needs. The zero value is usable: Run fills in the defaults above.

func ConfigFromEnv

func ConfigFromEnv() Config

ConfigFromEnv reads the configuration the node passes in the container environment.

type Route added in v0.6.0

type Route struct {
	Port   int
	Target string // host:port on the task network
}

Route is one port the gateway listens on and the service inside the task it forwards to.

func ParseRoutes added in v0.6.0

func ParseRoutes(args []string) ([]Route, error)

ParseRoutes reads the gateway's arguments: PORT=HOST:PORT, one per exposed port.

Jump to

Keyboard shortcuts

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