Documentation
¶
Overview ¶
Package proc implements the magus "process adoption" mechanism: child magus processes detect MAGUS_DAEMON_SOCKET and forward work over a Unix-domain socket RPC, sharing the parent's cache, logger, and concurrency budget.
Index ¶
- Variables
- func AcquireService(ctx context.Context, addr, key string, svc spells.Service) error
- func AlreadyReported(err error) bool
- func CwdFromContext(ctx context.Context) string
- func DiscoverSocket(ctx context.Context) (string, error)
- func DiscoverSockets(ctx context.Context) ([]string, error)
- func ExitCode(err error) (int, bool)
- func Forward(ctx context.Context, args []string, version, root string) (int, error)
- func IsJob(ctx context.Context) bool
- func LeaseFromContext(ctx context.Context) string
- func LookupStableSocket(ctx context.Context) (string, bool)
- func NotAdopted(err error) bool
- func ReleaseService(ctx context.Context, addr, key string) error
- func ReloadConfig(ctx context.Context, addr string) (dropped, busy int, err error)
- func RootFromContext(ctx context.Context) string
- func RunChildSync(ctx context.Context, lim *cache.Limiter, fn func() error) error
- func Shutdown(ctx context.Context, addr string) error
- func SockDir() string
- func SocketLive(ctx context.Context, addr string) bool
- func StableSocketName() string
- func StopAllServices(ctx context.Context, addr string) (int, error)
- func SubmitJob(ctx context.Context, addr string, args []string, version string) (string, error)
- func WithCwd(ctx context.Context, cwd string) context.Context
- func WithLease(ctx context.Context, lease string) context.Context
- func WithRoot(ctx context.Context, root string) context.Context
- func WithSubOp(ctx context.Context, op *SubOp) context.Context
- type Call
- type DaemonAdmitter
- type Options
- type Server
- type ServiceHost
- type StatusReply
- type SubOp
- type Workspace
Constants ¶
This section is empty.
Variables ¶
var ( // ErrAlreadyAdopted is returned by New when MAGUS_DAEMON_SOCKET is already set. ErrAlreadyAdopted = errors.New("proc: already running under a parent magus") // ErrCycleDetected is set in runReply.Err when the same (target, project) pair is already in-flight. ErrCycleDetected = errors.New("proc: cycle detected in nested magus invocation") )
var ( // ErrNotAdoptable: the daemon cannot service this subcommand (only run and // affected adopt a daemon); the client runs it locally. ErrNotAdoptable error = ¬AdoptedError{"proc: subcommand not adoptable"} // ErrVersionMismatch: the client's build version differs from the daemon's. ErrVersionMismatch error = ¬AdoptedError{"proc: version mismatch between parent and child magus"} // ErrProtocolMismatch: the client sent an unrecognized non-empty Protocol value. ErrProtocolMismatch error = ¬AdoptedError{"proc: protocol version mismatch"} )
The not-adopted daemon sentinels. Their MESSAGE strings are the wire contract: the daemon serializes them and the client string-matches to rebuild the typed value (decodeWireError), so keep the messages stable across identifier renames.
var ErrMultipleServers = errors.New("multiple proc servers found; use --socket to select one")
ErrMultipleServers reports that discovery found several live proc servers and will not choose between them. A sentinel because a caller has to tell it apart from "nothing is running": several candidates and none send a reader somewhere different, and folding the first into the second reports a busy machine as an idle one.
Functions ¶
func AcquireService ¶
AcquireService asks the daemon at addr to start (or reuse) a shared service and keep it warm past this invocation, returning once it is ready. addr accepts a unix:// URL or a bare path.
func AlreadyReported ¶ added in v0.4.0
AlreadyReported reports whether err - or any error it wraps - says its failure has already been explained to the user, so its own text carries no information worth showing. A dispatch that printed a diagnostic and then returned a bare sentinel is the case: the sentinel's message describes magus's control flow, not the failure.
It exists because that fact has to cross a process boundary. The server sends the error's text in runReply.Err and the client prints it; without a way to ask, every adopted failure would report itself with whatever placeholder the sentinel carries. Same shape as NotAdopted above, for the same reason: the classification belongs on the error, not in a list of strings to match.
func CwdFromContext ¶
CwdFromContext returns the child's working directory stored by the proc server, or "".
func DiscoverSocket ¶
DiscoverSocket scans SockDir for a live magus-*.sock file, preferring the stable daemon socket. Used where exactly one server has to be chosen to talk to.
The stable socket short-circuits the scan, so a machine running the daemon plus ad-hoc per-process servers still resolves to the daemon rather than reporting an ambiguity.
func DiscoverSockets ¶ added in v0.4.0
DiscoverSockets returns every live proc-server address in SockDir, the stable daemon socket first. Each one is a separate concurrency pool, so a reporter (`magus status`) enumerates them instead of demanding the caller pick one.
func ExitCode ¶ added in v0.4.0
ExitCode reports the process status err - or any error it wraps - asks for, and whether it asked at all. Same shape as NotAdopted and AlreadyReported above, and for the same reason: the classification has to cross a process boundary that erases the Go type. The CLI's own error types (a usage misuse exits 2, never 1) are in another package proc must not import, so the daemon asks the error rather than naming them.
func Forward ¶
Forward dials MAGUS_DAEMON_SOCKET, delegates args, and returns the exit code. On any transport error callers should fall back to running locally. Pass "" for root when unknown; the daemon resolves it from Cwd.
func IsJob ¶ added in v0.2.0
IsJob reports whether ctx belongs to a background job (submitted via SubmitJob) rather than an adopted run. The daemon's dispatch handler branches on it.
func LeaseFromContext ¶ added in v0.4.0
LeaseFromContext returns the lease the adopted client was launched under, or "" when it claimed none or claimed one that failed validation.
A caller that also reads the environment channel must prefer this: it is the lease of the process that ASKED for the run, while the daemon's own environment describes whoever happened to start the daemon.
func LookupStableSocket ¶
LookupStableSocket returns the address of the stable daemon socket if alive; bool is false when absent.
func NotAdopted ¶ added in v0.2.0
NotAdopted reports whether err - or any error it wraps - is a call the daemon did not adopt (a non-adoptable subcommand, or a build/protocol mismatch on an otherwise adoptable one): the daemon answered but will not take the call, so a caller runs it locally and quietly instead of treating it as a failure. Prefer this over matching the individual sentinels: it stays correct as reasons are added and sees through wrapping. Errors that do not implement NotAdopted() (e.g. a transport failure) report false - treat those as genuine forward failures.
func ReleaseService ¶
ReleaseService tells the daemon at addr that this invocation no longer needs the shared service for key; the daemon keeps it warm and reaps it later. addr accepts a unix:// URL or a bare path.
func ReloadConfig ¶ added in v0.4.0
ReloadConfig asks the daemon to drop the workspaces it holds open, so the next command against each reopens it and re-reads its config. It reports how many were dropped and how many were left alone because a run was in flight.
The counterpart of StopAllServices: a partial reset that leaves the daemon running, for the case where editing magus.yaml would otherwise mean restarting it.
func RootFromContext ¶
RootFromContext returns the workspace root stored by the proc server, or "".
func RunChildSync ¶
RunChildSync yields the caller's concurrency slot for the duration of fn so a child magus process can acquire it, keeping the total budget flat. If lim is nil or no slot is held fn runs unchanged (avoids over-releasing the semaphore).
func Shutdown ¶
Shutdown dials the proc server at addr and requests a graceful shutdown. addr accepts a unix:// URL or a bare path.
func SockDir ¶
func SockDir() string
SockDir returns the directory where magus proc sockets are stored.
func SocketLive ¶ added in v0.2.0
SocketLive reports whether a daemon is currently accepting on addr, which may be a unix:// URL or a bare socket path. It is the shared liveness probe behind idempotent `server start` (skip when one is already up) and `server stop` verification (confirm the daemon is actually gone after a shutdown request). A malformed address is treated as not-live rather than an error, since callers only care whether a daemon answers.
func StableSocketName ¶
func StableSocketName() string
StableSocketName returns the file basename of the stable multi-workspace daemon socket.
func StopAllServices ¶
StopAllServices asks the daemon at addr to stop every service it hosts (leaving the daemon running) and returns how many were stopped. addr accepts a unix:// URL or a bare path.
func SubmitJob ¶ added in v0.2.0
SubmitJob dials the proc server at addr and submits a fire-and-forget background job - the daemon runs `magus <args>` asynchronously and this returns as soon as it is accepted, with the job's invocation id (a Dashboard deep-link). It scopes the job to the caller's working directory (computed here, like Forward, so there is no transposition-prone dir argument); the daemon walks up from it to the workspace root. Used by the VCS refresh hook, which must not block a checkout. addr accepts a unix:// URL or a path. version is the caller's build version; it is sent as an adoption identity (see adoptionIdentity) so a background job is version-gated exactly like a forwarded run - a stale dev daemon will not silently run a fresh client's job with the wrong code.
func WithCwd ¶ added in v0.2.0
WithCwd returns ctx carrying the client's working directory, readable via CwdFromContext.
func WithLease ¶ added in v0.4.0
WithLease returns ctx carrying the client's lease, readable via LeaseFromContext. An id failing types.ValidLeaseID - including the empty string a client that predates the field sends - stores nothing, so a reader sees "".
The validation is here rather than at the call site because the value crosses a socket any local process may dial: a lease id is exempt from the trail's redaction, so storing an unvalidated one would let the wire carry a credential onto an event line. Dropping it matches what trail.LeaseFromEnv does with a malformed environment value.
Types ¶
type Call ¶
type Call struct {
Args []string `json:"args"`
Workspace string `json:"workspace,omitempty"` // empty for pre-workspace-aware servers
StartedAt time.Time `json:"started_at,omitempty"` // zero for pre-timing-aware servers
SubOp string `json:"sub_op,omitempty"` // short label of what the call is doing now
Inv string `json:"inv,omitempty"` // the invocation id this call runs under; deep-links to its live log
}
Call describes a single adopted call currently executing.
type DaemonAdmitter ¶ added in v0.4.0
type DaemonAdmitter struct{ Addr string }
DaemonAdmitter reaches the machine budget in the daemon at Addr. It is the socket implementation of cache.MachineAdmitter, and the only thing that makes a magus running here answerable to a magus running in another worktree.
func (DaemonAdmitter) Drop ¶ added in v0.4.0
func (d DaemonAdmitter) Drop(ctx context.Context, waiter string)
Drop retires a waiter that gave up, for the same reason and with the same tolerance.
func (DaemonAdmitter) Release ¶ added in v0.4.0
func (d DaemonAdmitter) Release(ctx context.Context, id string)
Release returns a granted claim. Errors are dropped: a release that cannot be delivered is retired by the budget's own liveness reap, and a teardown must not fail over bookkeeping.
func (DaemonAdmitter) Request ¶ added in v0.4.0
func (d DaemonAdmitter) Request(ctx context.Context, waiter string, c types.MachineClaim) (types.MachineVerdict, error)
Request polls the budget on behalf of waiter.
type Options ¶
type Options struct {
Handler func(ctx context.Context, args []string) error // required; ctx carries Root/Cwd
Context context.Context // nil → context.Background
Limiter *cache.Limiter // shared budget; nil → private limiter
Concurrency int // ignored when Limiter is set; 0 → default
Version string // "" disables version-mismatch check
Address string // "" → auto-generate in SockDir()
WorkspaceLister func() []Workspace // optional; used by daemon Status RPC
ServiceLister func() []types.StatusService // optional; hosted-services snapshot for the daemon Status RPC
ServiceHost ServiceHost // optional; hosts shared services across invocations (daemon only)
// OnJobDone, if set, is called after every BACKGROUND job (submitJob) completes - never for
// an adopted foreground run - with the job's args, wall-clock duration, and outcome. The
// ctx still carries Root/Cwd. The daemon uses it to record a KIND_JOB activity event; proc
// stays decoupled from the trail and cache layout.
OnJobDone func(ctx context.Context, args []string, dur time.Duration, err error)
// ConfigReloader, if set, drops the workspaces the daemon is holding open so the next
// command against each reopens it and re-reads its config. It reports how many were
// dropped and how many were left alone as busy. Only the daemon sets it; a per-process
// proc server holds one workspace for one invocation and has nothing to reload.
ConfigReloader func() (dropped, busy int)
// MachineBudget, if set, makes this server the arbiter of machine-wide admission:
// every magus on the host asks it before starting a step. Only the daemon sets it,
// and only one daemon exists per user, which is what makes the budget the machine's
// rather than a process's.
MachineBudget *cache.MachineBudget
}
Options configures the proc server created by New.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server listens on a Unix-domain socket and accepts forwarded RPC requests from child processes.
func New ¶
New constructs an unstarted Server; returns ErrAlreadyAdopted when MAGUS_DAEMON_SOCKET is set. Call Start to bind the socket.
func (*Server) Close ¶
func (s *Server) Close()
Close shuts down the listener, removes the socket file, and waits for all in-flight handlers. Safe to call multiple times.
func (*Server) Done ¶ added in v0.2.0
func (s *Server) Done() <-chan struct{}
Done returns a channel closed when the server has been Closed, whether by an RPC shutdown request or a signal. A blocking daemon loop selects on it so an RPC-driven `magus server stop` unblocks the process the same way a signal does: without it the shutdown handler tears down the listener but the process keeps running, since the listener's context is a sibling of the process context, not its parent.
func (*Server) IdleFor ¶ added in v0.4.0
IdleFor reports how long since a client last asked this server for anything, and whether it is doing nothing right now. A daemon nobody asked for uses the pair to decide it is no longer wanted; see the admission self-exit in cmd/magus.
Busy covers work in flight AND the machine budget, because a daemon holding claims is serving runs that are not talking to it: they took their claim, went quiet for the length of a build, and will come back to release it. Exiting under them would drop every claim on the machine.
type ServiceHost ¶
type ServiceHost interface {
// Acquire starts (or reuses) the service identified by key, returning once it is
// ready, and increments its dependent count.
Acquire(ctx context.Context, key string, svc spells.Service) error
// Release drops one dependent of key; the host keeps it warm and reaps it later.
Release(key string)
// StopAll stops every hosted service and returns how many were stopped, leaving
// the daemon running.
StopAll() int
}
ServiceHost hosts long-running shared services on behalf of adopted magus invocations, keeping them warm across separate runs. The daemon supplies one via Options; a per-process proc server leaves it nil (no cross-invocation hosting). Acquire/Release mirror the ref-counted lifecycle of cache.Limiter and service.Registry, the shared vocabulary for held resources.
type StatusReply ¶
type StatusReply struct {
ParentPID int `json:"parent_pid"`
DaemonVersion string `json:"daemon_version,omitempty"`
Mode string `json:"mode,omitempty"` // "daemon" (multi-workspace) | "proc" (per-process)
Capacity int `json:"capacity"`
Running int `json:"running"`
Queued int `json:"queued"`
Calls []Call `json:"calls,omitempty"`
Workspaces []Workspace `json:"workspaces,omitempty"` // nil for per-process proc servers
// Services are the long-running shared services the daemon is hosting right now.
// Nil for a per-process proc server (no cross-invocation service host).
Services []types.StatusService `json:"services,omitempty"`
// Machine is the host-wide admission budget this daemon arbitrates: what every
// magus on the machine holds and who is queued for it. Nil for a per-process proc
// server, which arbitrates nothing beyond itself.
Machine *types.MachineSnapshot `json:"machine,omitempty"`
}
StatusReply carries a point-in-time view of the parent's pool.
func QueryStatus ¶
func QueryStatus(ctx context.Context, addr string) (*StatusReply, error)
QueryStatus dials the proc server at addr and returns a live pool snapshot. addr accepts a unix:// URL or a bare path.
type SubOp ¶
type SubOp struct {
// contains filtered or unexported fields
}
SubOp holds the current sub-operation label for an inflight request. Concurrent-safe; all methods are nil-safe.
func SubOpFromContext ¶
SubOpFromContext returns the SubOp in ctx, or nil.
type Workspace ¶
type Workspace struct {
Root string `json:"root"`
LoadedAt time.Time `json:"loaded_at"`
LastAccess time.Time `json:"last_access"`
// Live cache activity for this workspace's long-lived cache. Zero for pre-cache-aware
// daemons or an Inspect workspace with no cache.
CacheHit int `json:"cache_hit,omitempty"`
CacheMiss int `json:"cache_miss,omitempty"`
CacheError int `json:"cache_error,omitempty"`
CacheBytes int64 `json:"cache_bytes,omitempty"`
// Work the hits replayed instead of ran, summed from each entry's recorded duration.
CacheSavedMs int64 `json:"cache_saved_ms,omitempty"`
// SecretProvider is the selected provider spell's name; empty = built-in env provider.
SecretProvider string `json:"secret_provider,omitempty"`
}
Workspace describes one workspace currently loaded by the daemon.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package endpoint is the parsed-transport-address value type, split out of internal/proc as a leaf with no OS or daemon dependencies (only context/fmt/net/strings).
|
Package endpoint is the parsed-transport-address value type, split out of internal/proc as a leaf with no OS or daemon dependencies (only context/fmt/net/strings). |
|
Package run is the shared subprocess helper for magus spells.
|
Package run is the shared subprocess helper for magus spells. |