workspace

package
v0.2.46 Latest Latest
Warning

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

Go to latest
Published: Oct 8, 2026 License: MPL-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package workspace is the seam behind `workspace://<name>/<verb>` EXEC dispatch: an owned, stateful execution environment — a directory on the chassis host in dev (chassis/workspace/local), a Fly Sprite in the fleet (overlay) — that a tenant's stack addresses by name and runs commands in.

Where a compute:// nano-op is a pure JSON→JSON transform in a no-fs, no-network sandbox, a workspace keeps files between calls, has a full runtime, and reaches the public internet. It is lambda-shaped in cost — woken on exec, put to sleep when idle, destroyed after idle days — and its output is data: a non-zero exit is a successful dispatch whose result says "exit 3", not a chassis error.

Vocabulary: a Computer executes work; a Workspace is the owned, stateful environment that provides one; a Run is one wake→sleep; a Task spans runs. Verbs: create, wake, exec, checkpoint, sleep, destroy, attach, connect.

Providers self-register from their package's init() (the compute-engine and vector-store idiom); the chassis activates one with --workspace-provider plus a blank import. The processor talks to a Manager, never to a Provider directly; the Manager owns the identity table (Store) when one is wired.

Index

Constants

View Source
const (
	LeaseHeartbeatInterval = 60 * time.Second
	LeaseStaleAfter        = 2 * LeaseHeartbeatInterval
)

LeaseHeartbeatInterval is how often a live attachment heartbeats; a lease silent for LeaseStaleAfter (two intervals) is dead — the node crashed mid-session — and no longer counts as holding the workspace.

View Source
const (
	StatusCreated   = "created"
	StatusRunning   = "running"
	StatusWarm      = "warm"
	StatusCold      = "cold"
	StatusDestroyed = "destroyed"
)

Lifecycle states recorded in workspaces.status.

View Source
const (
	DefaultCols uint16 = 80
	DefaultRows uint16 = 24
)

DefaultCols and DefaultRows are the TTY geometry when the request leaves it unset.

View Source
const CodeNotFound = "not_found"

CodeNotFound is the Error code a provider returns when the workspace it was asked for does not exist on its side — reaped by another node, deleted by an operator, or lost with the machine. It is the ONE failure the Manager is allowed to heal by recreating (see Exec): every other error might be transient, and recreating on a transient error would silently replace a pony's files with an empty environment.

View Source
const CodeStackDirUnavailable = "stack_dir_unavailable"

CodeStackDirUnavailable is the Error code for an exec that asked for its stack tree and cannot have it: the provider cannot place one, the stack version carries none, or its bundle could not be read.

View Source
const DefaultMaxOutputBytes int64 = 1 << 20

DefaultMaxOutputBytes is the per-stream capture cap when Limits leaves it unset.

View Source
const MaxNameSegments = 4

MaxNameSegments bounds how deep a "/"-separated name may nest.

Variables

View Source
var ErrNotAllowed = errors.New("workspace: provider not enabled on this chassis")

ErrNotAllowed is returned when the configured provider is refused on this chassis (the local provider without --workspace-allow-local).

View Source
var ErrTimeout = errors.New("workspace: exec timed out")

ErrTimeout is returned by a Computer when the op's context ended before the command did. The processor reports it in-band as workspace.error.code = "timeout".

View Source
var ValidSignals = []string{"INT", "TERM", "HUP", "KILL", "QUIT", "USR1", "USR2"}

ValidSignals is the closed set of signal names a session accepts, the intersection of what the providers deliver.

View Source
var Verbs = []string{"create", "wake", "exec", "checkpoint", "sleep", "destroy", "attach", "connect"}

Verbs is the closed vocabulary after the last "/" of a workspace ref. "attach" binds a live interactive session (a PTY) and "connect" a workspace-local service (see Services) to the WebSocket run that fires them; both are valid only inside such a run.

Functions

func AppStack

func AppStack(stack string) string

AppStack maps a routed stack name to the stack that OWNS the workspace. A stack is one app across inlets: a web request runs as `<stack>`, a mail delivery as `<stack>/_mail`, a WebSocket session as `<stack>/_websocket`. Those `_`-nested inlet sub-stacks share the app's workspace rather than each getting one of their own — the same rule `txco://kv` follows for its namespace (chassis/server/kv.go appStackNamespace), and for the same two reasons: an app's machine should be the same machine whichever inlet the request came in on, and a `/` cannot be spelled in a provider-side identifier anyway.

func ID

func ID(tenant, stack, name string) string

ID is the deterministic primary key for a workspace identity, so every node derives the same row without a lookup.

func IsNotFound

func IsNotFound(err error) bool

IsNotFound reports whether err says the workspace is gone.

func IsSignal

func IsSignal(sig string) bool

IsSignal reports whether sig is one of ValidSignals.

func IsVerb

func IsVerb(s string) bool

IsVerb reports whether s is one of Verbs.

func ParseRef

func ParseRef(s string) (name, verb string, ok bool)

ParseRef parses a `workspace://<name>/<verb>` EXEC value. The verb is the segment after the LAST "/", so a name may itself contain "/" (`workspace://pony/paris/exec` → name "pony/paris", verb "exec"). ok is false for any other shape: missing scheme, empty name, empty verb, or a verb outside Verbs. Name validity is ValidateName's job — the name may still be replaced by `WITH workspace = …` before it is checked.

func ParseServiceEntry

func ParseServiceEntry(raw string) (name string, port int, err error)

ParseServiceEntry parses one "name=port" operator entry.

func ProviderName

func ProviderName(tenant, stack, name string) string

ProviderName derives a provider-side identifier for (tenant, stack, name): a readable prefix `<tenant>-<stack>-<name with / → ->` truncated to 40 characters, then "-" and the first 8 hex of sha256(tenant\x00stack\x00name) so two identities can never collide after truncation. At most 49 characters — a DNS label with room for a provider suffix.

func Register

func Register(name string, c Constructor)

Register adds a provider constructor. Called from a provider package's init().

func SortedEnv

func SortedEnv(env map[string]string) []string

SortedEnv renders an environment map as sorted KEY=VALUE pairs, the shape os/exec and the fleet SDKs take. Sorted so two execs with the same env produce the same argv (stable traces, stable tests).

func TTYEnv

func TTYEnv(env map[string]string) map[string]string

TTYEnv returns env with TERM set for a terminal session when the request did not set one — a curses program with no TERM renders nothing useful. The input map is not modified.

func ValidateName

func ValidateName(name string) error

ValidateName checks a workspace name: 1–4 "/"-separated segments, each matching ^[a-z0-9][a-z0-9-]{0,62}$, none containing "--", none equal to a verb (so `workspace://exec/exec` cannot be read two ways).

Types

type CappedWriter

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

CappedWriter is the output sink every provider hands its command. In its default (buffered) form it keeps the first max bytes and flags the rest as dropped; writes never fail, so a child process never sees EPIPE from the cap — it just loses the tail of its output. In its streaming form (NewStreamWriter) it retains nothing and forwards every write to the caller's writer, where a write error IS propagated: the client is gone, so the command should stop.

Count() is the produced-byte total either way, so a provider reports the same figure whether the bytes were kept or streamed.

func NewCappedWriter

func NewCappedWriter(max int64) *CappedWriter

NewCappedWriter returns a writer that keeps at most max bytes (≤ 0 means DefaultMaxOutputBytes).

func NewStreamWriter

func NewStreamWriter(out io.Writer) *CappedWriter

NewStreamWriter returns a writer that forwards every write to out and retains nothing — the `WITH stream = true` path, where the bytes are already on their way to the client and must not also accumulate here.

func (*CappedWriter) Bytes

func (c *CappedWriter) Bytes() []byte

Bytes returns what was kept — nil for a stream writer, which keeps nothing.

func (*CappedWriter) Count

func (c *CappedWriter) Count() int64

Count is how many bytes the command wrote, kept or not.

func (*CappedWriter) Truncated

func (c *CappedWriter) Truncated() bool

Truncated reports whether any byte was dropped (never true while streaming: nothing is capped).

func (*CappedWriter) Write

func (c *CappedWriter) Write(p []byte) (int, error)

type Checkpointer

type Checkpointer interface {
	Checkpoint(ctx context.Context, h Handle, comment string) (string, error)
}

Checkpointer is the optional capability behind the checkpoint verb. A provider advertises it by listing "checkpoint" in Capabilities and implementing this interface; the returned id is provider-scoped.

type Computer

type Computer interface {
	Exec(ctx context.Context, req ExecRequest, lim Limits) (ExecResult, error)
}

Computer is a woken workspace that can run a command.

type Config

type Config struct {
	// LocalRoot is the local provider's root directory
	// (--workspace-local-root): <root>/<tenant>/<stack>/<name>.
	LocalRoot string
	// MaxOutputBytes is the per-stream capture cap (--workspace-max-output-bytes).
	MaxOutputBytes int64
}

Config carries backend-selecting options resolved from chassis config. A backend reads only the fields it needs (same posture as compute. EngineConfig and vector.Config).

type Constructor

type Constructor func(Config) (Provider, error)

Constructor builds a Provider from resolved config.

type Dialer

type Dialer interface {
	DialService(ctx context.Context, svc Service) (net.Conn, error)
}

Dialer is the optional capability behind the connect verb: a woken workspace that hands back a byte stream to one of its own local services. As with Starter, a provider lists "connect" in Capabilities for the boot log, but the gate is this interface assertion.

type Error

type Error struct {
	Code    string
	Message string
}

Error is a coded provider failure. The processor surfaces Code verbatim as workspace.error.code, so providers can say "capacity", "bad_request", "provider" and the rule author can gate on it.

func (*Error) Error

func (e *Error) Error() string

type ExecRequest

type ExecRequest struct {
	Command string
	Args    []string
	Stdin   []byte
	Cwd     string
	Env     map[string]string
	Timeout time.Duration

	// StdoutTo, when set, receives the command's stdout AS IT IS PRODUCED
	// instead of it being captured into ExecResult.Stdout — the streaming
	// path (`WITH stream = true`). Providers write to it directly, so each
	// write carries the provider's own chunking: a pipe read for the local
	// provider, one WebSocket frame for a fleet provider. The result then
	// reports StdoutBytes and leaves Stdout nil, so a large build log never
	// lands in the envelope, the trace, or a continuation.
	//
	// A write error stops the copy and surfaces as a transport failure. The
	// output cap does not apply (nothing accumulates); stderr is unaffected
	// — still captured and still capped.
	StdoutTo io.Writer

	// TTY allocates a pseudo-terminal for the command (`WITH tty = true`).
	// Many tools behave differently without one — progress rendering,
	// colour, pagers, a login flow that refuses to read a password from a
	// pipe — and this is how an agent gets the ordinary one-shot exec with
	// a terminal attached. A terminal has ONE stream, so stderr is merged
	// into stdout and ExecResult.Stderr comes back empty. Cols/Rows are the
	// initial geometry; 0 means 80×24. Requires a Computer that implements
	// Starter; the Manager reports "unsupported" otherwise.
	TTY  bool
	Cols uint16
	Rows uint16

	// Tree, when set, is the stack version's own directory (chassis/stackdir),
	// asked for with `WITH cwd = "$TXCO_STACK_DIR"`. The Manager has the
	// computer place it before the command starts, sets TXCO_STACK_DIR to
	// its path and starts the command there, with Cwd (clean, relative) below
	// it. Providers never see it set.
	Tree *Tree
}

ExecRequest is one command to run inside a woken workspace. Exactly one of Command (run via the workspace's shell) or Args (an argv, no shell) is set. Cwd is relative to the workspace root. Env is added to the provider's base environment verbatim. Timeout mirrors the ctx deadline for providers that need it as a value.

func (ExecRequest) Geometry

func (r ExecRequest) Geometry() (cols, rows uint16)

Geometry returns the requested TTY size with the defaults applied.

type ExecResult

type ExecResult struct {
	Exit            int
	Stdout          []byte
	Stderr          []byte
	StdoutTruncated bool
	StderrTruncated bool
	WallMS          int64

	// Recreated is set when the workspace was gone at the provider and the
	// Manager made a fresh one to run this command in — the files from
	// before are lost, and a rule may want to say so.
	Recreated bool

	// StdoutBytes counts the stdout bytes the command produced. It equals
	// len(Stdout) on the buffered path; on the streaming path
	// (ExecRequest.StdoutTo) Stdout is nil and this is how much reached
	// the client.
	StdoutBytes int64
}

ExecResult is what a command produced. Exit is the process exit code (-1 when unknown: killed by the timeout, or the process never ran). Stdout/Stderr are capped at Limits.MaxOutputBytes; the *_Truncated flags say when the cap dropped bytes.

func RunSession

func RunSession(sess ExecSession, req ExecRequest, lim Limits) (ExecResult, error)

RunSession drives a session the way a one-shot exec would: feed req.Stdin, drain Stdout into a capped buffer (or req.StdoutTo when streaming), wait for the exit, and shape the ExecResult exactly as Computer.Exec does. This is how `exec WITH tty = true` runs — the same result, with a terminal behind it.

type ExecSession

type ExecSession interface {
	Stdin() io.WriteCloser
	Stdout() io.Reader
	// Resize changes the terminal geometry of a TTY session; an error on a
	// non-TTY session.
	Resize(cols, rows uint16) error
	// Signal delivers a named signal: INT, TERM, HUP, KILL, QUIT, USR1, USR2.
	Signal(sig string) error
	// Wait blocks until the process ends and reports how. Safe to call more
	// than once; every call returns the same answer.
	Wait() (ExecResult, error)
	// Close ends the session whatever the process is doing: kill, a grace
	// period for the exit to land, then the transport is dropped. Idempotent.
	Close() error
}

ExecSession is one running process. The ctx handed to Start bounds it the way an exec's ctx bounds an exec: when it ends the process is killed.

Stdout is the caller's to drain — output is a stream by definition, so Wait's ExecResult carries Exit, WallMS and (for a non-TTY session) the captured, capped stderr, and leaves Stdout empty. A TTY session merges stderr into Stdout and reports Stderr empty. Stdin is a WriteCloser so a non-TTY session can be sent EOF; a PTY has no EOF to send and ignores Close.

type GrantReacher added in v0.2.31

type GrantReacher interface {
	ReachesGrants() bool
}

GrantReacher is the optional capability behind `exec WITH grant`: a provider whose commands run on the chassis's own machine, and so can reach the socket and the files a run grant is exercised through. A provider lists "grant" in Capabilities, but as with Starter the gate is this interface.

A provider whose commands run elsewhere does not implement it, and the op refuses: a grant handed to a command that cannot use it is a token left in an environment for nothing.

type Handle

type Handle struct {
	Provider string
	Ref      string
	Name     string
}

Handle is a provider-side reference to a created workspace. Ref is the provider's own id (a sprite name, a local directory); Name echoes Spec.Name for logging.

type Lease

type Lease struct {
	ID            string // the attachment id (hxid)
	Tenant        string
	Stack         string // the OWNING (app) stack, not the inlet sub-stack
	Name          string
	WorkspaceID   string // ID(tenant, stack, name)
	Kind          string // "pty"
	SessionID     string // the WebSocket session holding the socket
	NodeID        string // the chassis node holding it
	RunID         string
	StartedAt     time.Time
	ExpiresAt     time.Time
	LastHeartbeat time.Time
	ReleasedAt    *time.Time
}

Lease is one granted attachment to a workspace: who holds it, on which node, until when, and when it last proved it was alive. Rows outlive the binding (released_at is set, never deleted) so an admin view can answer "who was in this machine, when" — the same posture as the workspaces table itself.

A lease is what the reaper will consult (D9 of the PTY design): a workspace with a live lease is in use whatever its last_used_at says. Until that lands the heartbeat also touches last_used_at, so the reaper that exists today never reaps a workspace someone is sitting in.

func (Lease) Live

func (l Lease) Live(now time.Time) bool

Live reports whether the lease holds the workspace at now: not released, not past its expiry, and heard from within LeaseStaleAfter.

type Limits

type Limits struct {
	// MaxOutputBytes caps captured stdout and stderr, each. 0 = provider
	// default (1 MiB).
	MaxOutputBytes int64
}

Limits are per-exec caps the Manager hands every Computer.

type Manager

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

Manager is what the processor drives: it owns the provider, the identity table (when a Store is wired), and turns "run this in workspace X" into lookup → create-if-needed → wake → exec, minting run ids along the way. Without a Store the identity lives in a per-process cache (dev); with one it survives restarts and is shared across nodes.

func NewManager

func NewManager(p Provider, lim Limits, store *Store) *Manager

NewManager builds a Manager over a Provider with per-exec limits. store may be nil (no durable identity — the per-process cache only).

func (*Manager) Checkpoint

func (m *Manager) Checkpoint(ctx context.Context, spec Spec, comment string) (string, Handle, error)

Checkpoint snapshots the workspace through the provider's Checkpointer and records the returned reference; the handle comes back too so the caller can stamp which computer was snapshotted. Providers without the capability report unsupported.

func (*Manager) Create

func (m *Manager) Create(ctx context.Context, spec Spec) (Handle, error)

Create makes sure the workspace exists (idempotent) and returns its handle without waking it.

func (*Manager) Destroy

func (m *Manager) Destroy(ctx context.Context, spec Spec) error

Destroy removes the workspace, marks its row, and forgets its handle; the next exec starts fresh.

func (*Manager) Dial

func (m *Manager) Dial(ctx context.Context, spec Spec, svc Service) (net.Conn, Handle, string, error)

Dial wakes the workspace and opens a byte stream to one of its local services through the provider's Dialer. The ctx bounds the connection the way Start's bounds a session: when it ends, the connection is closed. The run id is minted or reused exactly as for an exec, and the identity table is touched, so a live connection counts as use. A provider without the Dialer capability reports "unsupported"; a workspace gone at the provider heals as Exec does.

func (*Manager) Exec

func (m *Manager) Exec(ctx context.Context, spec Spec, req ExecRequest) (ExecResult, Handle, string, error)

Exec runs req in the workspace spec names: lookup/create, wake, exec, record. It returns the provider handle and the run id alongside the result so the processor can stamp provenance. A non-nil error is a transport or provider failure — never a non-zero exit, which is data in ExecResult.

func (*Manager) Provider

func (m *Manager) Provider() Provider

Provider exposes the backend (for capability checks and logging).

func (*Manager) Services

func (m *Manager) Services() *Services

Services returns the table (never nil).

func (*Manager) SetServices

func (m *Manager) SetServices(s *Services)

SetServices installs the table the connect verb resolves against; the built-ins alone until it is called.

func (*Manager) Sleep

func (m *Manager) Sleep(ctx context.Context, spec Spec) error

Sleep asks the provider to park the workspace. A no-op on providers that sleep implicitly.

func (*Manager) Start

func (m *Manager) Start(ctx context.Context, spec Spec, req ExecRequest) (ExecSession, Handle, string, error)

Start opens a live session in the workspace spec names — lookup/create, wake, Start, record — and hands it back with the provider handle and the run id, for a caller that will hold the process open (an interactive attachment). The ctx bounds the SESSION, not this call: the process is killed when it ends, so pass one that lives as long as the binding should. Same one-shot not_found heal as Exec. Providers without Starter report "unsupported".

func (*Manager) Status

func (m *Manager) Status(ctx context.Context, spec Spec) (Status, error)

Status reports the provider's view of the workspace.

func (*Manager) Store

func (m *Manager) Store() *Store

Store exposes the identity table, if any (admin listings).

func (*Manager) Wake

func (m *Manager) Wake(ctx context.Context, spec Spec) (Handle, string, error)

Wake warms the workspace ahead of a task's first exec and returns the run id that exec will run under.

type Provider

type Provider interface {
	Name() string
	// Capabilities lists what this provider can do: "exec" always;
	// "network" when Spec.Network is honored; "checkpoint" when the
	// provider also implements Checkpointer.
	Capabilities() []string
	Create(ctx context.Context, spec Spec) (Handle, error)
	Wake(ctx context.Context, h Handle) (Computer, error)
	Sleep(ctx context.Context, h Handle) error
	Destroy(ctx context.Context, h Handle) error
	Status(ctx context.Context, h Handle) (Status, error)
}

Provider is a workspace backend. Create must be idempotent (creating an existing workspace returns its handle). Sleep is a no-op where the provider sleeps implicitly.

func Open

func Open(name string, cfg Config) (Provider, error)

Open constructs the named provider. Unknown name is a startup error listing what is available (so a misconfigured --workspace-provider fails loudly).

type Row

type Row struct {
	ID            string // sha256(tenant\0stack\0name) hex — see ID
	Tenant        string // slug
	Stack         string
	Name          string
	Provider      string
	ProviderRef   string
	Runtime       string
	Network       string
	Status        string
	RunID         string
	CheckpointRef string
	CreatedAt     time.Time
	LastUsedAt    time.Time
	DestroyedAt   *time.Time
}

Row is one workspace identity: (tenant, stack, name) → the provider's reference, plus the lifecycle bookkeeping the chassis keeps about it.

type RunReporter

type RunReporter interface {
	NewRun() bool
}

RunReporter is implemented by a Computer that can tell whether waking it started a new run (the provider reported the environment was not running). The Manager mints a new run id when it says so, even inside the warm window.

type Service

type Service struct {
	Name        string
	Port        int // on the workspace's loopback; the provider dials inside the workspace
	Description string
}

Service is one named endpoint on a workspace's OWN loopback that a stack may bind to a WebSocket session with `workspace://<name>/connect WITH service = "<name>"`. The name is the whole vocabulary a stack has: no host, port or scheme is reachable from a WITH value, so envelope data — including a model's output that reached one — can pick a service the chassis knows about and nothing else. That is what keeps connect an attachment rather than a tunnel.

func (Service) Addr

func (s Service) Addr() string

Addr is the loopback address the provider dials for the service.

type Services

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

Services is the closed name → Service table the connect verb resolves against.

func DefaultServices

func DefaultServices() *Services

DefaultServices is the built-in table alone.

func NewServices

func NewServices(extra []string) (*Services, error)

NewServices builds the table: the built-ins plus each operator entry ("name=port"). A malformed entry, a port outside 1–65535, a duplicate, or an attempt to redefine a built-in is an error — configuration, not data, so the caller decides whether that is fatal.

func (*Services) Lookup

func (s *Services) Lookup(name string) (Service, bool)

Lookup resolves a service by name.

func (*Services) Names

func (s *Services) Names() []string

Names lists the known services, sorted, for error messages and the boot log.

type Spec

type Spec struct {
	Tenant  string
	Stack   string
	Name    string
	Runtime string
	Network string // "public" (default) | "none"
}

Spec identifies a workspace: the (tenant, stack, name) triple is its identity; Runtime and Network are creation-time hints a provider may honor ("" = provider default).

type Starter

type Starter interface {
	Start(ctx context.Context, req ExecRequest, lim Limits) (ExecSession, error)
}

Starter is the optional capability behind a live session, implemented by a woken Computer: a process whose stdin the caller holds while it runs, whose output arrives as it is produced, and which can be resized and signalled by name. It is what a TTY exec runs through (RunSession) and what an interactive attachment binds to. A provider also lists "session" (and "tty") in Capabilities, but that string is advertisement for the boot log only — the gate is this interface assertion.

Exec stays the one-shot path. Folding it onto Start is attractive and is deliberately NOT done: the local process-group kill + WaitDelay and the fleet provider's detached-context kill dance are exactly the code that breaks quietly.

type Status

type Status struct {
	// State is one of created | running | warm | cold | destroyed.
	State    string
	LastUsed time.Time
}

Status is a provider's view of a workspace's lifecycle state.

type Store

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

Store is the thin façade over the workspaces table (part of the shared RUNTIME DB, alongside tenant_sources — identity is runtime state that must live where the authoritative writes go). It carries the dialect for `?`→`$n` rebinding and a clock seam for tests, mirroring source.Store.

func NewStore

func NewStore(db *sql.DB, d registry.Dialect) *Store

NewStore builds a Store over the opened runtime DB and its dialect. A nil dialect defaults to SQLite (the in-tree default).

func (*Store) EnsureSchema

func (s *Store) EnsureSchema(ctx context.Context) error

EnsureSchema creates the workspaces table + indexes if absent. Prod gets the table from the runtime migration (0026 / overlay 0029); this exists so tests and the overlay reaper's own connection can stand it up without the migration runner. The DDL is the portable subset the migration uses.

func (*Store) Get

func (s *Store) Get(ctx context.Context, tenant, stack, name string) (*Row, error)

Get returns the row for (tenant, stack, name), or (nil, nil) when there is none.

func (*Store) GetLease

func (s *Store) GetLease(ctx context.Context, leaseID string) (*Lease, error)

GetLease returns one lease by id, or (nil, nil).

func (*Store) Heartbeat

func (s *Store) Heartbeat(ctx context.Context, leaseID string, at time.Time) error

Heartbeat records that the attachment is still alive at `at`.

func (*Store) InsertLease

func (s *Store) InsertLease(ctx context.Context, l Lease) error

InsertLease records a newly granted attachment.

func (*Store) List

func (s *Store) List(ctx context.Context, tenant string, includeDestroyed bool, limit int) ([]Row, error)

List returns rows, newest use first; tenant "" lists every tenant.

func (*Store) ListIdle

func (s *Store) ListIdle(ctx context.Context, before time.Time, limit int) ([]Row, error)

ListIdle returns live rows (not destroyed) whose last use is before `before`, oldest first — the reaper's scan.

func (*Store) ListLeases

func (s *Store) ListLeases(ctx context.Context, tenant string, includeReleased bool, limit int) ([]Lease, error)

ListLeases returns leases newest first; tenant "" lists every tenant; includeReleased adds ended ones.

func (*Store) ListLive

func (s *Store) ListLive(ctx context.Context, workspaceID string, now time.Time) ([]Lease, error)

ListLive returns the leases that hold workspaceID at now (see Lease.Live) — what the reaper asks before destroying, and what an admin view shows as ATTACHED.

func (*Store) MarkDestroyed

func (s *Store) MarkDestroyed(ctx context.Context, id string, at time.Time) error

MarkDestroyed flips the row to destroyed at `at`; the row is kept so the identity's history survives and a later exec recreates in place.

func (*Store) ReleaseLease

func (s *Store) ReleaseLease(ctx context.Context, leaseID string, at time.Time) error

ReleaseLease ends the lease at `at` (idempotent: a released lease stays released at its first release time).

func (*Store) SetCheckpoint

func (s *Store) SetCheckpoint(ctx context.Context, id, ref string) error

SetCheckpoint records the provider's id for the latest checkpoint.

func (*Store) Touch

func (s *Store) Touch(ctx context.Context, id string, at time.Time, runID, status string) error

Touch records an exec: last_used_at, the run id it ran under, and the status the provider reported (running when unknown).

func (*Store) Upsert

func (s *Store) Upsert(ctx context.Context, r Row) error

Upsert records a (re)created workspace: INSERT, or on the identity key UPDATE the provider columns, reset status, and clear destroyed_at (a recreated workspace reuses its row). checkpoint_ref and run_id are left alone by an upsert of the same provider; a recreate after destroy starts with the provider's fresh environment, so the caller passes empty values and they are written.

type Tree added in v0.2.39

type Tree struct {
	Digest string
	Open   func(ctx context.Context) ([]byte, error)
}

Tree is a stack version's directory as one bundle (chassis/stackdir): its digest, and how to read the bundle when the computer does not hold it yet.

type TreeHolder added in v0.2.39

type TreeHolder interface {
	PlaceTree(ctx context.Context, t Tree) (string, error)
}

TreeHolder is the optional capability behind ExecRequest.Tree, implemented by a woken Computer: make the tree present on this computer, read-only, and return its path there. Idempotent per digest and safe to call concurrently. A provider without it answers CodeStackDirUnavailable.

type WarmProvider

type WarmProvider interface {
	WarmThreshold() time.Duration
}

WarmProvider is implemented by providers whose computer stays warm for a while after an exec before it sleeps (a fleet machine that idles before it parks). The Manager reuses the previous run id while the gap since the last exec is within the threshold — one run spans the warm window. Not implemented (or 0) means one run per exec.

Directories

Path Synopsis
Package local is the dev/self-host workspace provider: a workspace is a directory under --workspace-local-root, and exec runs the command as the chassis's own uid with that directory as HOME and cwd.
Package local is the dev/self-host workspace provider: a workspace is a directory under --workspace-local-root, and exec runs the command as the chassis's own uid with that directory as HOME and cwd.

Jump to

Keyboard shortcuts

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