Documentation
¶
Index ¶
- Constants
- Variables
- func CheckUV() error
- func EnsureProject(ctx context.Context, dir string) error
- func EnsurePython(version string) error
- func IsSynthesizedProject(dir string) bool
- func SanitizedEnv() []string
- func Sync(ctx context.Context, dir string) error
- func SyncR(ctx context.Context, bundleDir string) error
- type CgroupReadopter
- type ContainerInfo
- type DockerRuntime
- func (r *DockerRuntime) AppBindHost() string
- func (r *DockerRuntime) HostPreparesDeps() bool
- func (r *DockerRuntime) HostProvidesAppData() bool
- func (r *DockerRuntime) InspectPID(containerID string) (int, error)
- func (r *DockerRuntime) ListByLabel(labelFilter string) ([]ContainerInfo, error)
- func (r *DockerRuntime) PublishedHostPort(containerID string) (int, error)
- func (r *DockerRuntime) RemoveContainer(id string) error
- func (r *DockerRuntime) RemoveHandle(handle RunHandle) error
- func (r *DockerRuntime) Resume(_ context.Context, handle RunHandle) (ReplicaEndpoint, error)
- func (r *DockerRuntime) RunOnce(ctx context.Context, p StartParams, logWriter io.Writer) (ExitInfo, error)
- func (r *DockerRuntime) SetSnapshot(enabled bool, reclaimMinFraction float64)
- func (r *DockerRuntime) Signal(handle RunHandle, sig syscall.Signal) error
- func (r *DockerRuntime) Start(_ context.Context, p StartParams, logWriter io.Writer) (ReplicaEndpoint, error)
- func (r *DockerRuntime) Stats(ctx context.Context, handle RunHandle) (float64, uint64, error)
- func (r *DockerRuntime) Suspend(_ context.Context, handle RunHandle) (bool, error)
- func (r *DockerRuntime) Wait(ctx context.Context, handle RunHandle) error
- type DurableDataReporter
- type EnvResolver
- type ExitInfo
- type ExitVerdict
- type GopsutilSampler
- type InventoryItem
- type LogFile
- type LogReader
- type Manager
- func (m *Manager) Adopt(slug string, info ProcessInfo, handle RunHandle)
- func (m *Manager) All() []*ProcessInfo
- func (m *Manager) AllForSlug(slug string) []*ProcessInfo
- func (m *Manager) AppBindHostFor(tier string) string
- func (m *Manager) AutoInstrumentAppsDefault() bool
- func (m *Manager) EvictReplicaIfWorker(slug string, index int, workerID string)
- func (m *Manager) ForceEntry(slug string, info ProcessInfo)
- func (m *Manager) GetReplica(slug string, index int) (*ProcessInfo, bool)
- func (m *Manager) HandleReplica(slug string, index int) (RunHandle, bool)
- func (m *Manager) HostPreparesDepsFor(tier string) bool
- func (m *Manager) LastExit(slug string, index int) (ExitVerdict, bool)
- func (m *Manager) LogReader(slug string, index int) (*LogReader, bool)
- func (m *Manager) LogTail(slug string, index, n int) string
- func (m *Manager) PlanPlacement(tier, slug string, count int) []string
- func (m *Manager) RegisterRuntime(tier string, rt Runtime)
- func (m *Manager) ResolveAppEnv(slug string) ([]string, error)
- func (m *Manager) ResourceEnforcement(tiers ...string) (memory, cpu bool)
- func (m *Manager) Resume(slug string, index int) (ReplicaEndpoint, error)
- func (m *Manager) RunningContainerIDs() map[string]bool
- func (m *Manager) RuntimeForTier(tier string) Runtime
- func (m *Manager) SetAppDataRoot(root string) error
- func (m *Manager) SetAutoInstrumentAppsDefault(v bool)
- func (m *Manager) SetDefaultTier(name string)
- func (m *Manager) SetEnvResolver(r EnvResolver)
- func (m *Manager) SetPlatformDefaultEnvResolver(r PlatformDefaultEnvResolver)
- func (m *Manager) SetSharedMountResolver(r SharedMountResolver)
- func (m *Manager) SetStopGrace(d time.Duration)
- func (m *Manager) Start(p StartParams) (*ProcessInfo, error)
- func (m *Manager) Status(slug string) (*ProcessInfo, error)
- func (m *Manager) Stop(slug string) error
- func (m *Manager) StopAll() error
- func (m *Manager) StopReplica(slug string, index int) error
- func (m *Manager) Suspend(slug string) (bool, error)
- func (m *Manager) SuspendReplica(slug string, index int) (bool, error)
- func (m *Manager) TierHasDurableDataFor(tier string) bool
- func (m *Manager) TransportForWorker(tier, nodeID string) http.RoundTripper
- type NativeRuntime
- func (r *NativeRuntime) AppBindHost() string
- func (r *NativeRuntime) ConsumeOOMKill(pid int) bool
- func (r *NativeRuntime) HostPreparesDeps() bool
- func (r *NativeRuntime) HostProvidesAppData() bool
- func (r *NativeRuntime) ReadoptCgroup(slug string, index, pid int) error
- func (r *NativeRuntime) ReadoptWarm(slug string, index, pid int) error
- func (r *NativeRuntime) ResourceEnforcement() (memory, cpu bool)
- func (r *NativeRuntime) Resume(_ context.Context, handle RunHandle) (ReplicaEndpoint, error)
- func (r *NativeRuntime) RunOnce(ctx context.Context, p StartParams, logWriter io.Writer) (ExitInfo, error)
- func (r *NativeRuntime) SetIsolation(level sandbox.Level)
- func (r *NativeRuntime) SetSnapshot(enabled bool, reclaimMinFraction float64)
- func (r *NativeRuntime) Signal(handle RunHandle, sig syscall.Signal) error
- func (r *NativeRuntime) Start(_ context.Context, p StartParams, logWriter io.Writer) (ReplicaEndpoint, error)
- func (r *NativeRuntime) Stats(_ context.Context, handle RunHandle) (float64, uint64, error)
- func (r *NativeRuntime) Suspend(_ context.Context, handle RunHandle) (bool, error)
- func (r *NativeRuntime) Wait(ctx context.Context, handle RunHandle) error
- type PartialInventoryError
- type PlatformDefaultEnvResolver
- type ProcessInfo
- type ReplicaEndpoint
- type ReplicaInventory
- type ReplicaPlacer
- type ReplicaTransporter
- type ResourceEnforcer
- type RunHandle
- type Runtime
- type RuntimeSampler
- type Sampler
- type SharedMount
- type SharedMountResolver
- type Snapshotter
- type StartParams
- type Stats
- type Status
- type TaskRef
- type TierAssignment
- type WarmReadopter
Constants ¶
const ( // LabelManaged marks every resource launched by this control plane. // Value is always "true". LabelManaged = "shinyhub.managed" // LabelSlug is the app slug that owns the replica. LabelSlug = "shinyhub.slug" // LabelReplicaIndex is the zero-based replica index within the pool. LabelReplicaIndex = "shinyhub.replica_index" // LabelTier is the tier name the replica belongs to. LabelTier = "shinyhub.tier" // LabelProvider is the runtime provider name (e.g. "docker", "fargate"). LabelProvider = "shinyhub.provider" // LabelDeploymentID is the deployment row ID that placed this replica. LabelDeploymentID = "shinyhub.deployment_id" // LabelAppVersion is the app version string stamped at deploy time. LabelAppVersion = "shinyhub.app_version" // LabelContentDigest is the SHA-256 content digest of the deployed bundle. LabelContentDigest = "shinyhub.content_digest" // LabelPort is the port the app binds inside the replica so recovery can // rebuild the full route URL from the resource alone. LabelPort = "shinyhub.port" // LabelMaxSessions is the per-replica active-connection hard cap persisted on // the container so re-adoption after an agent restart restores the same limit. // Value is the decimal integer cap; absent or unparseable means no cap. LabelMaxSessions = "shinyhub.max_sessions" )
Label keys stamped on every managed replica container or task. All three backends (docker, remote_docker, fargate/ECS) write and read these same keys so the lifecycle layer can reconcile any backend identically.
const DefaultLogMaxSize = 5 << 20
DefaultLogMaxSize is the per-app log file size cap (5 MB). When exceeded, the file is rotated to app.log.1 and a fresh file is started.
const DefaultTier = "local"
DefaultTier is the tier name a replica runs under when StartParams.Tier is empty. Single-node deployments use exactly this one tier.
const SynthesizedProjectMarker = ".shinyhub-synthesized-project"
SynthesizedProjectMarker is a sentinel EnsureProject drops next to a pyproject.toml it generated from a requirements.txt. It distinguishes a synthesized project (valid only where this host prepared the deps and synced the .venv) from one the author shipped (valid everywhere).
Variables ¶
var ErrNoLiveWorker = errors.New("no live worker for tier")
ErrNoLiveWorker is returned (wrapped) when a tier-bound remote runtime has no live worker to place a replica on. The watcher treats it as a zero-cost failure: a missing worker is an infrastructure gap, not the app's fault, so it must not consume the crash-restart budget.
var ErrReplicaAlreadyRunning = errors.New("replica already running")
ErrReplicaAlreadyRunning is returned (wrapped) by Manager.Start when the target slug+index slot is already running. The watcher treats it as zero-cost: a re-placement that races a slot already (re)filled is a no-op, not a failure.
var ErrReplicaNotFound = errors.New("replica not found")
ErrReplicaNotFound is returned (wrapped) by Manager.StopReplica when the slug+index slot has no live entry. Callers that distinguish an already-gone replica from a real stop failure (e.g. autoscale scale-down) match this sentinel: a missing entry is benign, while any other error means the replica may still be running and its control-plane state must be left intact.
var ErrReplicaNotSuspended = errors.New("replica not suspended")
ErrReplicaNotSuspended is returned (wrapped) by Manager.Resume when the target slot is not in a suspended state, so there is nothing to resume.
var ErrRuntimeNotSnapshotter = errors.New("runtime does not support snapshot")
ErrRuntimeNotSnapshotter is returned (wrapped) by Manager.Suspend/Resume when the replica's tier runtime does not implement Snapshotter. Callers fall back to Stop (hibernate) or a cold RunReplica (wake).
Functions ¶
func EnsureProject ¶ added in v0.8.12
EnsureProject converts a requirements.txt-only Python app into a uv project so it gains a native uv.lock (fully pinned, hashed, requires-python-aware) and launches in project mode. Reproducibility then comes from one mechanism - uv.lock - for both author-provided and requirements-based apps.
It is a no-op when a pyproject.toml is already present (the author's, or a prior conversion) or when there is no requirements.txt to convert. On a failed `uv add` it removes the half-built project so the app falls back cleanly to requirements mode rather than launching against an incomplete environment.
func EnsurePython ¶
EnsurePython runs `uv python install <version>` if version is non-empty.
func IsSynthesizedProject ¶ added in v0.8.12
IsSynthesizedProject reports whether the pyproject.toml in dir was generated by EnsureProject (rather than shipped by the app author).
func SanitizedEnv ¶ added in v0.5.1
func SanitizedEnv() []string
SanitizedEnv returns an allow-listed subset of the current process environment. It is the single source of truth for the env base of every app-controlled code path: app processes, dependency installation (uv/renv), and post-deploy hooks. Server secrets (SHINYHUB_AUTH_SECRET, the deploy token, OAuth/OIDC client secrets, and cloud credentials such as AWS_SECRET_ACCESS_KEY) must never reach code that a deployer can influence, so only known-safe variables pass through.
Types ¶
type CgroupReadopter ¶ added in v0.9.0
type CgroupReadopter interface {
// ReadoptCgroup re-registers the deterministic app-<slug>-<index> cgroup for
// an adopted pid when it exists and still contains the pid, and seeds its OOM
// baseline. Best-effort: returns nil when there is no such cgroup (no limit
// was set, or warm-wake is off and no base exists).
ReadoptCgroup(slug string, index, pid int) error
}
CgroupReadopter re-registers a replica's per-app resource-limit cgroup after a server restart, INDEPENDENT of warm-wake. Without it, an adopted replica that has a memory/CPU limit (but no warm-wake) loses its cgroup mapping, so the runtime can neither tear it down nor detect an OOM-kill for it. Only the native runtime implements it; container runtimes hold this state in their daemon.
type ContainerInfo ¶
ContainerInfo is a summary of a running container used during process recovery.
type DockerRuntime ¶
type DockerRuntime struct {
// contains filtered or unexported fields
}
DockerRuntime implements Runtime using the Docker Engine API. Each app runs in its own container with the bundle directory mounted at /app.
func NewDockerRuntime ¶
func NewDockerRuntime(socketPath, pythonImage, rImage, networkMode string) (*DockerRuntime, error)
NewDockerRuntime creates a DockerRuntime connected to socketPath. networkMode must be "bridge" or "host" (validated by config). Returns an error if the socket is unreachable (verified by pinging the API).
func (*DockerRuntime) AppBindHost ¶ added in v0.2.2
func (r *DockerRuntime) AppBindHost() string
AppBindHost returns the address the app should bind inside the container. In host-network mode the container shares the host loopback, so 127.0.0.1 keeps the "only the proxy can reach the app" boundary intact. In bridge mode the container has its own network namespace; the listener must bind 0.0.0.0 inside the container so the published 127.0.0.1:port mapping on the host can route to it.
func (*DockerRuntime) HostPreparesDeps ¶ added in v0.2.2
func (r *DockerRuntime) HostPreparesDeps() bool
HostPreparesDeps reports false: dependency installation happens inside the container (via uv/Rscript present in the base image), so callers must not run uv sync / renv::restore on the host.
func (*DockerRuntime) HostProvidesAppData ¶ added in v0.6.1
func (r *DockerRuntime) HostProvidesAppData() bool
HostProvidesAppData reports that the local Docker runtime provisions app data on the control-plane host and mounts it into the container.
func (*DockerRuntime) InspectPID ¶
func (r *DockerRuntime) InspectPID(containerID string) (int, error)
InspectPID returns the host PID of the container's init process.
func (*DockerRuntime) ListByLabel ¶
func (r *DockerRuntime) ListByLabel(labelFilter string) ([]ContainerInfo, error)
ListByLabel returns containers with the given label filter (JSON filter string).
func (*DockerRuntime) PublishedHostPort ¶ added in v0.6.1
func (r *DockerRuntime) PublishedHostPort(containerID string) (int, error)
PublishedHostPort returns the host port the container's published bind port maps to, or 0 when nothing is published. The data-plane proxy uses this to rebuild its target after an agent restart re-adopts a running container.
func (*DockerRuntime) RemoveContainer ¶ added in v0.8.13
func (r *DockerRuntime) RemoveContainer(id string) error
RemoveContainer force-removes a container by ID. force=true handles a paused container, so recovery can reap an orphaned frozen warm container. Satisfies the lifecycle.ContainerLister capability. An empty ID is a no-op.
func (*DockerRuntime) RemoveHandle ¶ added in v0.5.1
func (r *DockerRuntime) RemoveHandle(handle RunHandle) error
RemoveHandle force-removes the container behind handle. Long-running app containers are created without AutoRemove (so a crash leaves the container inspectable for recovery), so they must be explicitly removed once the Manager has confirmed the process exited on stop/replace; otherwise stopped containers accumulate. Satisfies the optional containerRemover capability the Manager type-asserts for. A nil/empty ID or an already-gone container is treated as success.
func (*DockerRuntime) Resume ¶ added in v0.8.12
func (r *DockerRuntime) Resume(_ context.Context, handle RunHandle) (ReplicaEndpoint, error)
Resume thaws a paused container. It is idempotent: a running, non-paused container returns immediately. pause/unpause leaves the route URL unchanged, so the returned endpoint carries an empty URL and the Manager preserves the known route.
func (*DockerRuntime) RunOnce ¶ added in v0.2.1
func (r *DockerRuntime) RunOnce(ctx context.Context, p StartParams, logWriter io.Writer) (ExitInfo, error)
RunOnce creates a one-shot container with AutoRemove=true, starts it, and blocks on /containers/{id}/wait. Ctx cancel sends SIGTERM via the kill API, then SIGKILL after a 10-second grace.
func (*DockerRuntime) SetSnapshot ¶ added in v0.8.12
func (r *DockerRuntime) SetSnapshot(enabled bool, reclaimMinFraction float64)
SetSnapshot enables warm-wake (freeze + cgroup reclaim) and sets the reclaim-success threshold. Called once at startup from buildRuntime.
func (*DockerRuntime) Signal ¶
func (r *DockerRuntime) Signal(handle RunHandle, sig syscall.Signal) error
func (*DockerRuntime) Start ¶
func (r *DockerRuntime) Start(_ context.Context, p StartParams, logWriter io.Writer) (ReplicaEndpoint, error)
func (*DockerRuntime) Suspend ¶ added in v0.8.12
Suspend freezes the container (docker pause) and reclaims its resident memory to swap via cgroup v2 memory.reclaim, returning freed=true only when the reclaimed fraction meets the configured threshold. On any non-(true,nil) result it unpauses so the caller's Stop path operates on a normal container. When snapshot is disabled it reports ErrRuntimeNotSnapshotter so the watcher hibernates via Stop.
type DurableDataReporter ¶ added in v0.9.5
type DurableDataReporter interface {
// TierHasDurableData reports whether app-data on this tier survives task
// restart/hibernation and is shared across replicas.
TierHasDurableData() bool
}
DurableDataReporter is an optional capability for runtimes whose per-app data dir may NOT survive a restart or be shared across replicas. A runtime that does not implement it is treated as durable (native, docker, and remote workers all back the data dir with a persistent host directory). Only the Fargate runtime implements it, returning false unless a durable backend (S3 Files, or an operator-asserted volume) is configured. The durable-data guard consumes it via Manager.TierHasDurableDataFor to block deploying a data-using app onto a tier that would silently lose its data.
type EnvResolver ¶
EnvResolver returns the per-app environment for the given slug as two "KEY=VALUE" slices: env holds non-secret values, secretEnv holds decrypted secret values. They are kept separate so a runtime can deliver secrets out of band (e.g. the Fargate task definition's secrets block) instead of as plaintext. It is called during Start to inject per-app env before launch.
type ExitInfo ¶ added in v0.2.1
type ExitInfo struct {
Code int // exit code; -1 if Signaled
Signaled bool // true if killed by signal (e.g. SIGKILL after timeout)
}
ExitInfo summarizes how a one-shot process ended.
type ExitVerdict ¶ added in v0.9.0
type ExitVerdict struct {
OOMKilled bool
// MemoryLimitMB is the enforced per-replica limit at the time of the exit
// (0 when unknown, e.g. an adopted process). The watcher falls back to the
// app's stored limit when this is 0.
MemoryLimitMB int
At time.Time
}
ExitVerdict records how a replica's most recent process exited. It survives the entry being replaced on restart so the watcher can still name an OOM-kill after the crash-restart budget is spent.
type GopsutilSampler ¶
type GopsutilSampler struct {
// contains filtered or unexported fields
}
GopsutilSampler is the production Sampler that reads from the OS via gopsutil. It caches process handles by PID so gopsutil can compute CPU deltas across successive Sample calls (gopsutil needs two measurements per *Process instance).
func (*GopsutilSampler) Purge ¶ added in v0.8.14
func (g *GopsutilSampler) Purge(alive map[int32]struct{})
Purge evicts cached process handles for PIDs not present in alive. The GopsutilSampler caches a *gops.Process per PID so CPU% can be computed as a delta across calls, and it only drops an entry when a Sample for that PID fails. A long-running caller that samples only currently-running PIDs (the metrics-history collector) never re-samples an exited PID, so without periodic pruning the cache grows unbounded as PIDs churn. Callers pass the set of live PIDs each cycle; everything else is dropped.
func (*GopsutilSampler) Sample ¶
func (g *GopsutilSampler) Sample(handle RunHandle) (Stats, error)
Sample returns CPU% and RSS for the process identified by handle.PID. The first call for a PID always returns CPUPercent = 0.0 because gopsutil needs two measurements to compute a delta. Subsequent calls return the real value.
type InventoryItem ¶ added in v0.6.1
type InventoryItem struct {
ContainerID string
Labels map[string]string
// Running is true for any task not in STOPPED state (PROVISIONING, PENDING,
// or RUNNING). It is false only when the task has terminated. Consumers
// that need a routable URL must additionally check URL != "".
Running bool
URL string
WorkerID string
}
InventoryItem describes one managed container as reported by a remote runtime's inventory. Recovery reconciles a replica row against these items by matching the slug/replica_index/deployment_id labels, then routes to URL. WorkerID names the worker that reported the container; with inventory aggregated across a tier's coexisting workers, recovery uses it to bind a replica row to its owning worker's container, so a same-labeled container on another worker is not adopted with the wrong worker's URL, handle, and transport.
Running means "not stopped": for the Fargate runtime a task in PROVISIONING, PENDING, or RUNNING state is reported as Running=true. Only STOPPED tasks are Running=false. This is intentional: a Fargate task that has not yet acquired an IP is not yet routable, but it is NOT gone and must not trigger re-placement. Consumers that need "routable now" must check URL != "" in addition to Running.
type LogFile ¶
type LogFile struct {
// contains filtered or unexported fields
}
LogFile is a size-capped, append-only log destination for one app process. It implements io.WriteCloser and is safe for concurrent writes from the stdout and stderr goroutines that the OS spawns when cmd.Stdout and cmd.Stderr are both set to the same writer.
func OpenLogFile ¶
OpenLogFile opens or creates the log file at path for appending.
type LogReader ¶
type LogReader struct {
// contains filtered or unexported fields
}
LogReader reads from an app log file on disk. Its Tail and Follow methods open independent read handles so they work regardless of whether the write side (LogFile) is open or closed.
func NewLogReader ¶
NewLogReader creates a reader for the log file at path.
func (*LogReader) Follow ¶
Follow sends new lines written to the log file to lines until ctx is cancelled. It polls the file at 100 ms intervals.
func (*LogReader) Tail ¶
Tail returns the last n lines from the log file in chronological order. It reads backward from the end in chunks, so the work is proportional to the size of the returned tail rather than the whole (up to multi-MB) file - the hot path for the log viewer and every new SSE follow connection.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager tracks running app processes as a pool of replicas per slug. entries maps slug → slice indexed by replica index; nil means that slot is down.
func NewManager ¶
NewManager returns an initialized Manager using the given Runtime as the default ("local") tier. Additional tiers are added via RegisterRuntime.
func (*Manager) Adopt ¶
func (m *Manager) Adopt(slug string, info ProcessInfo, handle RunHandle)
Adopt re-registers a process that was not started by this Manager instance (e.g. recovered after a server restart). It starts the exit-monitoring goroutine so crashed processes are detected normally.
func (*Manager) All ¶
func (m *Manager) All() []*ProcessInfo
All returns a snapshot of all tracked ProcessInfo entries across all slugs.
func (*Manager) AllForSlug ¶ added in v0.2.1
func (m *Manager) AllForSlug(slug string) []*ProcessInfo
AllForSlug returns per-replica info for one slug, preserving index order. Slots for down replicas are nil.
func (*Manager) AppBindHostFor ¶ added in v0.6.1
AppBindHostFor proxies to the runtime registered for the named tier so deploy code can construct the per-replica command with the right listen address. An empty or unregistered tier falls back to the default tier. See Runtime.AppBindHost for the contract.
func (*Manager) AutoInstrumentAppsDefault ¶ added in v0.8.5
AutoInstrumentAppsDefault reports the fleet-wide auto-instrumentation default. Per-app shinyhub.toml [tracing] auto overrides it at boot time.
func (*Manager) EvictReplicaIfWorker ¶ added in v0.6.2
EvictReplicaIfWorker removes a replica from the manager's view without signaling its runtime, freeing the slug+index slot so a re-placement Start succeeds. It is used when the backing worker is already gone (heartbeat down-sweep or admin revoke): unlike StopReplica it sends no signal, because dialing a dead worker would hang. The evicted entry's log file is closed under the lock; the entry's own (now stale) exit-monitor goroutine sees the slot nil and is a no-op.
Eviction is gated on the entry still being owned by workerID: a worker-loss pass can race a redeploy that already re-placed this slot onto a healthy worker (registering its route and starting a new manager entry before persisting the new replica row). Evicting unconditionally would drop that live replacement; so an entry owned by a different worker is left untouched. A no-op when the slot is already empty.
func (*Manager) ForceEntry ¶
func (m *Manager) ForceEntry(slug string, info ProcessInfo)
ForceEntry directly inserts a ProcessInfo without starting an exit-monitoring goroutine. Used in tests to inject state without starting a real process. For production recovery use Adopt, which starts the monitoring goroutine.
func (*Manager) GetReplica ¶ added in v0.2.1
func (m *Manager) GetReplica(slug string, index int) (*ProcessInfo, bool)
GetReplica returns a snapshot of the ProcessInfo for a specific replica.
func (*Manager) HandleReplica ¶ added in v0.2.1
HandleReplica returns the RunHandle for a specific replica, or false if not tracked.
func (*Manager) HostPreparesDepsFor ¶ added in v0.6.1
HostPreparesDepsFor proxies to the runtime registered for the named tier so deploy code can ask whether host-side dependency installation (uv sync, renv::restore) is expected before Start. An empty or unregistered tier falls back to the default tier. See Runtime.HostPreparesDeps for the contract.
func (*Manager) LastExit ¶ added in v0.9.0
func (m *Manager) LastExit(slug string, index int) (ExitVerdict, bool)
LastExit returns the most recent exit verdict for a replica (whether it was OOM-killed and the limit in force), or ok=false when none is recorded.
func (*Manager) LogReader ¶
LogReader returns a LogReader for a specific replica's log file. Returns false if no log file exists yet (replica has never been started).
func (*Manager) LogTail ¶ added in v0.8.20
LogTail returns the last n lines of a replica's log file joined by newlines, or "" when the log cannot be read. Used to capture a crash diagnostic (e.g. a Python traceback) when an app transitions to "crashed".
func (*Manager) PlanPlacement ¶ added in v0.7.0
PlanPlacement asks the tier's runtime to plan worker assignments for count replicas of slug, returning one target worker node id per replica in assignment order. It returns nil when the tier's runtime does not route to workers (native local tier), in which case replicas have no target worker and the runtime places them itself. Deploy calls this once up front so a concurrent pool boot spreads across workers instead of each replica self-placing against the same pre-deploy load snapshot.
func (*Manager) RegisterRuntime ¶ added in v0.6.1
RegisterRuntime adds or replaces the runtime for the named tier. Safe to call concurrently with RuntimeForTier lookups.
func (*Manager) ResolveAppEnv ¶ added in v0.10.4
ResolveAppEnv returns the app's stored per-app environment - non-secret and decrypted secret values combined into one KEY=VALUE slice - via the configured env resolver. It exists for app-controlled code paths that run outside Start (host-side dependency builds and post-deploy hooks) and have no out-of-band secret channel. Nil-safe: a nil Manager or unset resolver returns (nil, nil). A resolver error propagates so callers fail closed, matching Start.
func (*Manager) ResourceEnforcement ¶ added in v0.9.0
ResourceEnforcement reports whether per-app memory/CPU limits are actually enforced across the given tiers (an app may span several). A limit is reported enforced only when enforced on EVERY tier (AND), so an app that runs partly on a native host without cgroup delegation is correctly flagged. The native runtime is best-effort (gated on cgroup v2 delegation); container/remote runtimes apply hard limits, so a runtime that does not implement ResourceEnforcer is treated as enforcing both. With no tiers, the default tier is used.
func (*Manager) Resume ¶ added in v0.8.12
func (m *Manager) Resume(slug string, index int) (ReplicaEndpoint, error)
Resume restores a single suspended replica via the tier runtime's Snapshotter capability and returns its (possibly updated) route endpoint. The in-memory entry returns to StatusRunning with the resumed endpoint's URL/WorkerID/handle. Returns a wrapped ErrRuntimeNotSnapshotter, ErrReplicaNotSuspended, or ErrReplicaNotFound sentinel when the slot cannot be resumed, so the caller cold-boots it instead.
func (*Manager) RunningContainerIDs ¶ added in v0.5.1
RunningContainerIDs returns the set of container IDs the Manager currently has adopted across all slugs. Empty for native runtime (handles carry a PID, not a container ID). Used by the startup orphan-container sweep to decide which ShinyHub-labeled containers have no live owner.
func (*Manager) RuntimeForTier ¶ added in v0.6.1
RuntimeForTier returns the runtime backing the named tier, falling back to the default tier when tier is empty or unregistered. Exposed for recovery, which routes each replica's re-adoption to its tier's runtime (so one app's replicas can span a native default tier and a container-backed burst tier).
func (*Manager) SetAppDataRoot ¶ added in v0.2.1
SetAppDataRoot sets the root directory under which per-app persistent data directories live. Each Start resolves <root>/<slug>, ensures it exists, stamps it onto StartParams.AppDataPath, and symlinks <bundle_dir>/data to it. Injection of SHINYHUB_APP_DATA into the child env is the Runtime's responsibility (NativeRuntime uses the host path; DockerRuntime translates to the in-container mount path) — the Manager only owns the dir + symlink. An empty root disables the feature. Must be called before the manager begins starting processes; not safe to call concurrently with Start.
func (*Manager) SetAutoInstrumentAppsDefault ¶ added in v0.8.5
SetAutoInstrumentAppsDefault sets the fleet-wide default for launching Python apps under opentelemetry-instrument. Wired once at startup from tracing.auto_instrument_apps, before any deploys run, like the platform default env resolver. Must be called before Start; not safe to call concurrently with boots.
func (*Manager) SetDefaultTier ¶ added in v0.6.1
SetDefaultTier renames the default tier and rekeys the seed runtime under that name. NewManager registers the seed runtime under DefaultTier ("local"); when the config's first tier is named differently, call this once at startup so empty/unknown tiers still resolve to the seed runtime. A no-op when name is empty or already the default. Must be called before the manager begins starting processes; it is not safe to call concurrently with Start.
func (*Manager) SetEnvResolver ¶
func (m *Manager) SetEnvResolver(r EnvResolver)
SetEnvResolver sets the function used to inject per-app environment variables during Start. Must be called before the manager begins starting processes; it is not safe to call concurrently with Start.
func (*Manager) SetPlatformDefaultEnvResolver ¶ added in v0.4.1
func (m *Manager) SetPlatformDefaultEnvResolver(r PlatformDefaultEnvResolver)
SetPlatformDefaultEnvResolver sets the function that supplies platform-wide default env vars (currently OTEL_* tracing config). The returned values are prepended to the env so user-supplied per-app env wins on duplicate keys. Must be called before Start; not safe to call concurrently with Start.
func (*Manager) SetSharedMountResolver ¶ added in v0.2.1
func (m *Manager) SetSharedMountResolver(r SharedMountResolver)
SetSharedMountResolver sets the function used to resolve shared mounts during Start. Must be called before the manager begins starting processes; not safe to call concurrently with Start.
func (*Manager) SetStopGrace ¶ added in v0.8.26
SetStopGrace sets how long StopReplica waits after SIGTERM before escalating to SIGKILL. Must be called before the manager begins stopping processes; it is not safe to call concurrently with StopReplica.
func (*Manager) Start ¶
func (m *Manager) Start(p StartParams) (*ProcessInfo, error)
Start spawns a new process for the given slug and replica index. Returns an error if that replica is already running.
func (*Manager) Status ¶
func (m *Manager) Status(slug string) (*ProcessInfo, error)
Status returns the first running replica, or a synthetic stopped record. Callers that need per-replica info should use AllForSlug.
func (*Manager) Stop ¶
Stop signals all replicas for a slug to stop in parallel and waits for all to exit.
func (*Manager) StopAll ¶ added in v0.5.1
StopAll gracefully stops every tracked app across all slugs, concurrently. Used on server shutdown when server.shutdown_apps is "stop" so the host is left clean instead of with orphaned subprocesses/containers. Errors are aggregated; a failure to stop one app does not block the others.
func (*Manager) StopReplica ¶ added in v0.2.1
StopReplica signals a single replica to stop and waits for it to exit. If the process does not exit within the stop grace (default defaultStopGrace, configurable via SetStopGrace), SIGKILL is sent.
func (*Manager) Suspend ¶ added in v0.8.12
Suspend freezes every running replica of slug via the tier runtime's Snapshotter capability, releasing host RAM. It returns freed=true ONLY when every replica's warmed memory was released; in that case each frozen replica's in-memory status becomes StatusSuspended (the entry is kept - the process/ container is paused, not gone). If the runtime is not a Snapshotter, or any replica could not be freed, Suspend restores any replicas it had frozen (so the whole pool is back to a normal running state the caller can Stop) and returns freed=false, so the caller falls back to Stop (which always frees RAM).
func (*Manager) SuspendReplica ¶ added in v0.8.13
SuspendReplica freezes a single running replica via the tier runtime's Snapshotter, releasing its host RAM, and flips the in-memory entry to StatusSuspended on success. It is the per-replica analogue of Suspend, mirroring Resume's index-addressed shape, used by the warm pool to freeze drained replicas while the floor keeps serving.
Returns freed=true ONLY when the warmed memory was actually released. On any other result the driver has already restored the replica to a normally stoppable state (per the Snapshotter contract), so the entry is left StatusRunning and the caller falls back to StopReplica: (false, ErrRuntimeNotSnapshotter) when the tier runtime cannot snapshot, (false, nil) when too little was reclaimed, (false, err) on a driver error.
func (*Manager) TierHasDurableDataFor ¶ added in v0.9.5
TierHasDurableDataFor reports whether app-data on the named tier survives task restart/hibernation and is shared across replicas. A runtime that does not implement DurableDataReporter is treated as durable (native/docker/remote all back the data dir with a persistent host directory); only Fargate reports ephemeral storage when no durable backend is configured. An empty or unregistered tier falls back to the default tier. The durable-data guard uses this to block deploying a data-using app onto a tier that would lose its data.
func (*Manager) TransportForWorker ¶ added in v0.7.0
func (m *Manager) TransportForWorker(tier, nodeID string) http.RoundTripper
TransportForWorker returns the HTTP transport a tier's runtime requires for reaching replicas hosted by the named worker, or nil to use the default transport. Runtimes opt in by implementing ReplicaTransporter; routes are keyed per-worker so a replica is always dialed with its host worker's transport even when several workers serve the tier.
type NativeRuntime ¶
type NativeRuntime struct {
// contains filtered or unexported fields
}
NativeRuntime runs app processes as direct OS child processes.
func NewNativeRuntime ¶
func NewNativeRuntime() *NativeRuntime
NewNativeRuntime returns a ready-to-use NativeRuntime.
func (*NativeRuntime) AppBindHost ¶ added in v0.2.2
func (r *NativeRuntime) AppBindHost() string
AppBindHost returns "127.0.0.1": native processes share the host network and must only be reachable via the in-process proxy.
func (*NativeRuntime) ConsumeOOMKill ¶ added in v0.9.0
func (r *NativeRuntime) ConsumeOOMKill(pid int) bool
ConsumeOOMKill reports whether the pid's last exit was a kernel OOM-kill and clears the per-pid OOM bookkeeping. Implements the manager's oomReporter.
func (*NativeRuntime) HostPreparesDeps ¶ added in v0.2.2
func (r *NativeRuntime) HostPreparesDeps() bool
HostPreparesDeps reports true: native runtime executes app processes on the host using its PATH, so bundle dependencies must be installed locally before Start.
func (*NativeRuntime) HostProvidesAppData ¶ added in v0.6.1
func (r *NativeRuntime) HostProvidesAppData() bool
HostProvidesAppData reports that the native runtime provisions app data on the local host.
func (*NativeRuntime) ReadoptCgroup ¶ added in v0.9.0
func (r *NativeRuntime) ReadoptCgroup(slug string, index, pid int) error
ReadoptCgroup re-registers an adopted replica's per-app cgroup independent of warm-wake, so a limited replica adopted after a server restart can still be torn down and have its OOM-kills detected. Best-effort and idempotent: it no-ops when the delegated base is unavailable or the deterministic cgroup either does not exist or no longer holds the pid (i.e. the replica was uncapped). It re-seeds the OOM baseline so only post-readopt kills count.
func (*NativeRuntime) ReadoptWarm ¶ added in v0.8.17
func (r *NativeRuntime) ReadoptWarm(slug string, index, pid int) error
ReadoptWarm re-registers the per-app cgroup of a replica adopted from a prior process life (after a server restart), so warm-wake (Suspend/Resume) works for it again. The cgroup survives the restart on disk; only this runtime's in-memory appCgroups mapping is lost, and Adopt - unlike Start - never rebuilds it. ReadoptWarm reconstructs the deterministic app-<slug>-<index> directory under the delegated base, confirms the adopted PID is still a member, and re-registers the mapping. It is the adoption-time analogue of placeInAppCgroup.
Best-effort: ErrRuntimeNotSnapshotter when warm-wake is off or its base never came up (the caller stays silent; the replica hibernates via Stop as today); any other error means the cgroup is gone or no longer holds the PID (the caller logs and degrades).
func (*NativeRuntime) ResourceEnforcement ¶ added in v0.9.0
func (r *NativeRuntime) ResourceEnforcement() (memory, cpu bool)
ResourceEnforcement reports whether per-app memory / cpu limits are actually enforced on this host (the controller is delegated to the service), preparing the cgroup base on first call. The UI/API surface this so an operator is not misled into thinking a limit applies when cgroup delegation is absent.
func (*NativeRuntime) Resume ¶ added in v0.8.12
func (r *NativeRuntime) Resume(_ context.Context, handle RunHandle) (ReplicaEndpoint, error)
Resume thaws a previously suspended replica (SIGCONT). It is idempotent: SIGCONT on an already-running process group is a no-op. The PID and port are preserved, so the route URL is unchanged and the returned endpoint carries an empty URL for the Manager to preserve the known route. A vanished process group (ESRCH) is a genuine error so the caller cold-boots; its now-empty cgroup is reclaimed by the replica's Wait.
func (*NativeRuntime) RunOnce ¶ added in v0.2.1
func (r *NativeRuntime) RunOnce(ctx context.Context, p StartParams, logWriter io.Writer) (ExitInfo, error)
RunOnce blocks until the process exits or ctx is cancelled. On ctx cancel, the process group receives SIGTERM, then SIGKILL after a 10-second grace.
func (*NativeRuntime) SetIsolation ¶ added in v0.9.1
func (r *NativeRuntime) SetIsolation(level sandbox.Level)
SetIsolation sets the native process-isolation dial. Called once at startup from buildRuntime, before any Start. If isolation is requested on a platform with no enforcement backend (non-Linux), it warns and runs without it rather than failing to start apps.
func (*NativeRuntime) SetSnapshot ¶ added in v0.8.12
func (r *NativeRuntime) SetSnapshot(enabled bool, reclaimMinFraction float64)
SetSnapshot enables warm-wake (SIGSTOP freeze + per-app cgroup reclaim) and sets the reclaim-success threshold. Called once at startup from buildRuntime, before any Start. The delegated cgroup base is prepared lazily on the first Start that needs it (see ensureCgroupBase); if that preparation fails the runtime degrades gracefully and hibernates via Stop as before.
func (*NativeRuntime) Signal ¶
func (r *NativeRuntime) Signal(handle RunHandle, sig syscall.Signal) error
func (*NativeRuntime) Start ¶
func (r *NativeRuntime) Start(_ context.Context, p StartParams, logWriter io.Writer) (ReplicaEndpoint, error)
func (*NativeRuntime) Suspend ¶ added in v0.8.12
Suspend freezes a replica's process group (SIGSTOP) and reclaims its resident memory to swap via its per-app cgroup's memory.reclaim, returning freed=true only when the reclaimed fraction meets the configured threshold. On any non-(true,nil) result it sends SIGCONT so the process is left normally stoppable. When warm-wake is disabled or its cgroup base never came up it reports ErrRuntimeNotSnapshotter so the watcher hibernates via Stop; a replica that was started without a per-app cgroup reports (false, nil) for the same fallback without flagging the whole runtime as non-snapshotting.
type PartialInventoryError ¶ added in v0.7.0
type PartialInventoryError struct {
Workers []string
}
PartialInventoryError reports that a tier's aggregated inventory is incomplete: at least one worker was queried successfully, but Workers could not be reached. The returned items hold what the reachable workers reported. Recovery uses Workers to distinguish a replica whose container is genuinely gone (its owning worker reported and the container was absent) from one whose owning worker was merely unreachable (status unknown); the latter must not drive a live app to stopped.
func (*PartialInventoryError) Error ¶ added in v0.7.0
func (e *PartialInventoryError) Error() string
type PlatformDefaultEnvResolver ¶ added in v0.4.1
PlatformDefaultEnvResolver returns "KEY=VALUE" platform defaults that should be set BEFORE the user's per-app env, so user values win on duplicate keys. This is the slot for OTEL_* env vars that the operator configures platform-wide but each app may still override per-app via the env-var UI. Returning nil disables the hook.
type ProcessInfo ¶
type ProcessInfo struct {
Slug string
Index int
PID int
Port int
Status Status
Tier string
Provider string
EndpointURL string
WorkerID string
AppVersion string
DeploymentID int64
// OOMKilled is set when this replica's most recent exit was a kernel
// OOM-kill (it exceeded its memory limit). Used to surface a crash reason
// that names the limit rather than a generic crash.
OOMKilled bool
}
type ReplicaEndpoint ¶ added in v0.6.1
type ReplicaEndpoint struct {
URL string // route URL, e.g. "http://127.0.0.1:34521"
Provider string // "native" | "docker" (future: "remote_docker" | "fargate")
WorkerID string // stable identity: PID (stringified), container ID, task ARN
Handle RunHandle // operational handle
}
ReplicaEndpoint is the result of starting a replica: where the proxy routes to it, which provider owns it, a stable worker identity used for recovery, and the operational RunHandle for Signal/Wait/Stats/removal. A remote runtime returns a non-loopback URL here; local runtimes return http://127.0.0.1:<port>.
type ReplicaInventory ¶ added in v0.6.1
type ReplicaInventory interface {
Inventory(ctx context.Context) ([]InventoryItem, error)
}
ReplicaInventory is an optional capability for runtimes that can enumerate their live replicas without a host PID (remote workers). RecoverProcesses uses it to reconcile remote tiers by deployment id instead of InspectPID.
type ReplicaPlacer ¶ added in v0.7.0
ReplicaPlacer is the optional capability a worker-routing Runtime implements to plan where a batch of replicas should land. PlanPlacement returns one target worker node id per replica, in assignment order, spreading the batch across the tier's workers. Runtimes that do not route to workers (the native local tier) do not implement it.
type ReplicaTransporter ¶ added in v0.6.1
type ReplicaTransporter interface {
// ReplicaTransportForWorker returns the RoundTripper to use when dialing
// replicas hosted by the named worker, or nil to use the default transport
// (also returned when the worker is not a live host on this runtime's tier).
ReplicaTransportForWorker(nodeID string) http.RoundTripper
}
ReplicaTransporter is an optional capability for runtimes that route replica traffic through a non-default HTTP transport (for example a remote worker's mTLS tunnel). The proxy and health-check paths use this transport so that requests to the replica's reported URL authenticate correctly. The transport is per-worker: a tier may have several workers, and each replica's route must use the mTLS transport of the worker that actually hosts it.
type ResourceEnforcer ¶ added in v0.9.0
type ResourceEnforcer interface {
// ResourceEnforcement reports whether memory and cpu limits are enforced.
ResourceEnforcement() (memory, cpu bool)
}
ResourceEnforcer is the optional runtime capability to report whether per-app memory/CPU limits are ACTUALLY enforced on this host. Only the native runtime implements it (enforcement is best-effort, gated on cgroup v2 delegation); container/remote runtimes always enforce, so they do not implement it and the manager treats them as enforcing.
type RunHandle ¶
type RunHandle struct {
PID int // set by NativeRuntime
ContainerID string // set by DockerRuntime
}
RunHandle identifies a running app instance. Exactly one field is non-zero depending on the runtime in use.
type Runtime ¶
type Runtime interface {
// Start spawns a new process. logWriter receives combined stdout+stderr.
// The returned ReplicaEndpoint carries the route URL the proxy must use,
// the provider name, a durable worker identity, and the operational handle.
Start(ctx context.Context, p StartParams, logWriter io.Writer) (ReplicaEndpoint, error)
// Signal sends sig to the process or container identified by handle.
Signal(handle RunHandle, sig syscall.Signal) error
// Wait blocks until the process or container identified by handle exits.
Wait(ctx context.Context, handle RunHandle) error
// Stats returns CPU usage (percent, 0–100+) and RSS bytes for the handle.
Stats(ctx context.Context, handle RunHandle) (cpuPercent float64, rssBytes uint64, err error)
// RunOnce spawns a short-lived process from the same bundle/runtime context
// as Start, blocks until it exits or ctx is cancelled, and returns the
// exit info. Implementations MUST signal SIGTERM on ctx cancel and
// SIGKILL after a 10-second grace.
RunOnce(ctx context.Context, p StartParams, logWriter io.Writer) (ExitInfo, error)
// HostPreparesDeps reports whether bundle dependencies (uv sync,
// renv::restore) should be installed on the host before Start. Native
// runtimes use the host's PATH and need this; container runtimes prepare
// deps inside the image/container, so callers must NOT touch the host.
HostPreparesDeps() bool
// AppBindHost reports the address an app process should bind its listening
// socket to. Native and Docker host-network runtimes return "127.0.0.1" so
// only the in-process proxy can reach the app. Docker bridge-network
// runtimes return "0.0.0.0" so the published port mapping (which lives in
// the container's separate network namespace) is reachable from the host.
AppBindHost() string
// HostProvidesAppData reports whether the host running this Manager is
// responsible for provisioning the per-app data directory and shared-mount
// host paths. Local runtimes (native, docker on the control-plane host)
// return true. Remote runtimes return false: the worker provisions its own
// app-data, so the Manager must not create host directories or symlinks and
// must strip host paths before dispatching Start.
HostProvidesAppData() bool
}
Runtime abstracts how app processes are started and managed. NativeRuntime uses exec.Command; DockerRuntime uses the Docker Engine API.
type RuntimeSampler ¶
type RuntimeSampler struct {
Runtime Runtime
}
RuntimeSampler implements Sampler by delegating to Runtime.Stats. Used when DockerRuntime is active so stats are fetched via the Docker API.
type SharedMount ¶ added in v0.2.1
type SharedMount struct {
}
SharedMount is a read-only mount of another app's data dir into the consumer.
type SharedMountResolver ¶ added in v0.2.1
type SharedMountResolver func(slug string) ([]SharedMount, error)
SharedMountResolver returns the shared mounts for a slug. Empty slice means no mounts. Called once per Start; failures abort the start.
type Snapshotter ¶ added in v0.8.12
type Snapshotter interface {
// Suspend freezes the replica identified by handle and tries to release its
// warmed memory from host RAM. It returns freed=true ONLY when the warmed
// memory was actually released (driver-defined threshold). On any result
// other than (true, nil) - freed=false OR err != nil, including an error
// after a partial freeze - the driver MUST first restore the replica to a
// normally stoppable state so the caller's Stop path works without
// special-casing a frozen cgroup. The handle stays valid for a later Resume
// only on (true, nil).
Suspend(ctx context.Context, handle RunHandle) (freed bool, err error)
// Resume restores a previously suspended replica and returns its route
// endpoint (the same URL when the driver preserves the process/port in
// place). Resume MUST be idempotent: if the replica is already serving,
// return the current endpoint and nil error. On a genuine error the driver
// MUST tear down the stale frozen/suspended resource before returning, so the
// caller's cold-boot fallback cannot collide with or leak it.
Resume(ctx context.Context, handle RunHandle) (ReplicaEndpoint, error)
}
Snapshotter is an optional capability for runtimes that can freeze a running replica's warmed memory and restore it, skipping a cold restart on wake. A runtime that does not implement it uses the existing stop/cold-start path.
A runtime that implements Snapshotter must also ensure its Stop/Signal path can terminate a SUSPENDED replica - a frozen resource (e.g. a paused cgroup) does not deliver SIGTERM until it is thawed, so the runtime must unfreeze before killing (or kill the frozen resource directly). Until a real Snapshotter runtime is registered, suspended state never arises in production: Manager. Suspend returns ErrRuntimeNotSnapshotter and the watcher falls back to Stop.
type StartParams ¶
type StartParams struct {
Slug string
// AppID is the owning app's numeric DB id. It is used to namespace per-app
// external resources (e.g. Fargate secret store names and task-definition
// families) so a delete-then-recreate of the same slug never collides.
// Zero when unknown (paths that do not touch per-app external resources).
AppID int64
Index int
Tier string // runtime tier; empty => DefaultTier
Dir string
Command []string
Port int
// HostPublishPort, when non-zero, is the host port to publish the
// in-container bind Port to. The control plane allocates Port (baked into
// the command and PORT env); a remote worker allocates HostPublishPort on
// its own host. Zero means publish to the same port as Port (local case).
HostPublishPort int
Env []string
// SecretEnv carries decrypted secret env vars ("KEY=VALUE"), kept in a slice
// separate from Env. Every runtime currently injects SecretEnv as plaintext
// alongside Env (the native, Docker, and Fargate runtimes concatenate the
// two; a key is either secret or not, so the order is immaterial). The slice
// is kept distinct so the Fargate runtime can later route these values
// through the task definition's secrets block instead of plaintext task
// overrides; until then secret values are NOT hidden from ecs:DescribeTasks.
SecretEnv []string
AppDataPath string // host path to per-app data dir; empty disables data-dir wiring in runtime
MemoryLimitMB int // 0 = no limit
CPUQuotaPercent int // 0 = no limit; 100 = 1 full core
AppVersion string // app version stamped onto labels/metadata
DeploymentID int64 // owning deployment; 0 when unknown
ContentDigest string // bundle content digest; "" when unknown (remote runtime pulls by this)
// TargetWorker pins this replica to a specific worker node id. Deploy
// pre-plans a multi-replica pool's worker assignments up front (so a
// concurrent batch spreads instead of every replica self-placing onto the
// same least-loaded worker against an identical pre-deploy snapshot) and
// stamps the chosen worker here. Empty means the runtime self-places against
// live load, which is correct for a single-replica boot (e.g. a watchdog
// restart). Runtimes that do not route to workers ignore it.
TargetWorker string
// MaxSessions is the per-replica active-connection hard cap enforced at the
// worker data plane. 0 means no cap. Persisted as a Docker label so re-adoption
// after an agent restart restores the same limit.
MaxSessions int
// JobRunID, when non-zero, marks this as a one-shot scheduled-job run (via
// RunOnce, not Start). It namespaces the job's own cgroup (job-<slug>-<runID>)
// so a capped job never shares replica 0's app-<slug>-0 cgroup.
JobRunID int64
}
type TaskRef ¶ added in v0.7.0
type TaskRef struct {
ARN string
}
TaskRef identifies one Fargate task returned by a FargateTaskSweeper. It lives in the process package so both fargate.Runtime and lifecycle can use it without an import cycle (fargate imports process; lifecycle imports both fargate and process; placing TaskRef here breaks the fargate->lifecycle direction that would otherwise form a cycle).
type TierAssignment ¶ added in v0.6.1
TierAssignment binds a global replica index to the tier that should run it. Indexes are contiguous and unique across the whole app (a single global index space); the tier is an attribute, never folded into the index.
func ExpandPlacement ¶ added in v0.6.1
func ExpandPlacement(placement map[string]int, tierOrder []string, fallbackReplicas int, defaultTier string) ([]TierAssignment, error)
ExpandPlacement turns a per-tier replica-count map into a deterministic, contiguous list of (index, tier) assignments.
When placement is empty, all fallbackReplicas indexes are assigned to defaultTier, reproducing single-tier behavior exactly. When placement is non-empty, tiers are walked in tierOrder and each is allocated the next contiguous block of indexes; tiers with count 0 are skipped. Every tier in placement must appear in tierOrder. The resolved total must be at least 1.
type WarmReadopter ¶ added in v0.8.17
type WarmReadopter interface {
// ReadoptWarm re-registers the warm-wake state for an adopted replica. It
// returns ErrRuntimeNotSnapshotter when warm-wake is unavailable (the caller
// stays silent); any other error means the warm state could not be rebuilt
// (the caller logs and the replica hibernates via Stop).
ReadoptWarm(slug string, index, pid int) error
}
WarmReadopter is implemented by a runtime whose warm-wake state is held in this process's memory and is therefore lost when a replica is re-adopted after a server restart - the native runtime, whose per-app cgroup mapping Adopt does not rebuild the way Start does. Manager.Adopt calls ReadoptWarm best-effort so a re-adopted replica can be warm-frozen and warm-resumed again. Runtimes whose warm state survives a restart independently (e.g. Docker's daemon-held paused containers) do not implement it.