daemon

package
v0.144.4 Latest Latest
Warning

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

Go to latest
Published: Sep 18, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Overview

Package daemon owns the durable local lifecycle record for the WB daemon.

The record deliberately contains scheduler ownership, rather than command output, so a later ConnectRPC/gRPC transport and the MCP adapter can use the same queue handoff contract without reading a dashboard-only file.

Package daemon owns WB's durable local operation queue.

Index

Constants

View Source
const (
	// StateSchemaVersion is the version this build writes. Load accepts every
	// version in SupportedStateSchemaVersions: a running daemon's record must
	// stay readable across an upgrade, and refusing an older record would make
	// the daemon that wrote it look absent.
	StateSchemaVersion      = 2
	MinSupportedStateSchema = 1
	QueueSchemaVersion      = 1
)
View Source
const (
	ProtocolVersion = 1
	QueueSchema     = 1
)
View Source
const RawExecutionPolicyVersion = 1
View Source
const RuntimeDirName = "runtime"

RuntimeDirName is the directory inside WB's home that holds daemon runtime state: the local socket, the lifecycle record, and the daemon's log.

View Source
const SocketFileName = "daemon.sock"

SocketFileName is the local endpoint's name inside the runtime directory.

View Source
const StateFileName = "daemon-state.json"

StateFileName is the durable lifecycle record inside the runtime directory.

Variables

This section is empty.

Functions

func LegacyRuntimeDir added in v0.134.0

func LegacyRuntimeDir(projectsRoot string) string

LegacyRuntimeDirName reproduces the runtime directory WB used before the daemon consulted the home resolver: a literal ".wb" beneath the projects root. It exists so a daemon left there can be *detected* and reported rather than silently doubled. Nothing in this package writes to it.

It is spelled out here, rather than reusing wbhome, precisely because it is the shape that must not be produced again: wbhome resolves a home, and this is a fixed historical path.

func LegacyStatePath added in v0.134.0

func LegacyStatePath(projectsRoot string) string

LegacyStatePath is the lifecycle record a daemon wrote before the runtime directory followed WB's home. It exists for detection only; nothing here reads it as this build's own state.

func LoadRawExecutionPolicy added in v0.105.0

func LoadRawExecutionPolicy(path, projectsRoot string) (bool, error)

LoadRawExecutionPolicy enables raw subprocesses only through a protected, explicit administrator opt-in outside the agent-writable projects tree.

func OperationsDir added in v0.134.0

func OperationsDir(projectsRoot string) (string, error)

OperationsDir is the daemon's durable operation store.

It is derived from the same home as every other runtime artefact, and it is passed to NewService explicitly rather than resolved inside it: a constructor that reads the environment makes every caller share one store, which is both untestable in isolation and wrong for a library.

func ParseProcStatBootTime added in v0.134.0

func ParseProcStatBootTime(contents string) (time.Time, bool)

ParseProcStatBootTime extracts the btime (boot time, in Unix seconds) from the contents of /proc/stat.

func ParseProcStatStartTicks added in v0.134.0

func ParseProcStatStartTicks(contents string) (uint64, bool)

ParseProcStatStartTicks extracts the process start time from the contents of a Linux /proc/<pid>/stat file, in clock ticks since boot.

The comm field is wrapped in parentheses and may itself contain spaces and parentheses, so the fields are counted from the last ')' rather than by splitting the whole line: a process named "my (odd) name" must not shift every field after it. Start time is field 22 of the record, which is the twentieth field after the state field that follows comm.

func ProcessStartFromProcStat added in v0.134.0

func ProcessStartFromProcStat(ticks uint64, bootTime time.Time) time.Time

ProcessStartFromProcStat converts a /proc start-tick count and the system boot time into an absolute start time.

func ProcessStartTime added in v0.134.0

func ProcessStartTime(pid int) (time.Time, bool)

ProcessStartTime observes when pid started, so a recorded PID can be checked against the process now holding it. It reports false when the platform cannot answer, which callers must surface as unknown rather than as a match.

func RawExecutionPolicyPath added in v0.105.0

func RawExecutionPolicyPath() (string, error)

func RequireRawExecutionPolicy added in v0.105.0

func RequireRawExecutionPolicy(path, projectsRoot string) error

RequireRawExecutionPolicy re-reads and validates the protected host policy. Callers must invoke it at every execution boundary so revocation is immediate.

func RuntimeDir added in v0.134.0

func RuntimeDir(projectsRoot string) (string, error)

RuntimeDir resolves the daemon's runtime directory through WB's one home resolver, so a WB_HOME move moves the daemon with every other subsystem.

This is the whole point of the function: the daemon previously built its runtime path by joining the projects root with a literal ".wb", which meant that when WB_HOME moved — including the symlink-then-revert migration of 2026-09-15 — every subsystem followed and the daemon stayed behind, still serving a socket inside a directory the rest of WB had abandoned.

func SocketPath added in v0.134.0

func SocketPath(projectsRoot string) (string, error)

SocketPath is the home-derived local endpoint of the daemon.

The path is also an identity: unlike the shared loopback port it names the one home whose daemon may own it, which is why status reports it rather than inferring ownership from whoever answers on the port.

func StatePath added in v0.134.0

func StatePath(projectsRoot string) (string, error)

StatePath is the runtime directory's lifecycle record.

func SupportedStateSchemaVersions added in v0.134.0

func SupportedStateSchemaVersions() []int

SupportedStateSchemaVersions lists the record versions this build can read.

Types

type Provenance

type Provenance struct {
	Executable string `json:"executable"`
	SHA256     string `json:"sha256"`
	Version    string `json:"version"`
	Revision   string `json:"revision,omitempty"`
	Built      string `json:"built,omitempty"`
}

Provenance identifies the exact executable trusted to own a daemon generation. SHA256 is intentionally included even when the released version is known: a development binary can otherwise look identical to a release.

func ProvenanceForExecutable

func ProvenanceForExecutable(executable, version, revision, built string) (Provenance, error)

ProvenanceForExecutable produces exact local evidence for a running binary.

func (Provenance) SameBinary

func (p Provenance) SameBinary(other Provenance) bool

type Queue

type Queue struct {
	SchemaVersion int         `json:"schema_version"`
	Generation    uint64      `json:"generation"`
	Owner         Provenance  `json:"owner"`
	OwnerToken    string      `json:"owner_token"`
	HandoffFrom   *Provenance `json:"handoff_from,omitempty"`
	HandoffAt     *time.Time  `json:"handoff_at,omitempty"`
}

Queue describes durable queue ownership. Operations are added by the async scheduler lane; lifecycle code preserves this object byte-for-byte apart from a fenced owner/generation transition.

type Service added in v0.105.0

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

Service implements the generated ConnectRPC service and persists every state transition before it is returned to the caller.

func NewService added in v0.105.0

func NewService(projectsRoot, operationsDirectory, build, generation string, authorizeRaw func() error) (*Service, error)

NewService opens the durable operation store at operationsDirectory for the projects root the daemon serves.

The store's location is an argument rather than something NewService resolves from the environment: the daemon's runtime directory follows WB's home (see RuntimeDir and OperationsDir), and a constructor that looked that up itself would silently put every caller — including every test in this package — on one shared store.

func (*Service) CancelOperation added in v0.105.0

func (*Service) CompleteOperation added in v0.106.0

func (*Service) DisconnectWorker added in v0.106.0

func (*Service) GetDaemonInfo added in v0.105.0

func (*Service) GetOperation added in v0.105.0

func (*Service) HeartbeatOperation added in v0.106.0

func (*Service) LeaseOperation added in v0.106.0

func (*Service) RegisterWorker added in v0.106.0

func (*Service) StartLeaseRecovery added in v0.106.0

func (service *Service) StartLeaseRecovery(ctx context.Context)

StartLeaseRecovery watches running worker leases even when no client is polling an operation. The daemon owns only this recovery clock; execution remains in the connected worker process.

func (*Service) SubmitOperation added in v0.105.0

func (*Service) WaitOperation added in v0.105.0

type State

type State struct {
	SchemaVersion int        `json:"schema_version"`
	Status        Status     `json:"status"`
	PID           int        `json:"pid,omitempty"`
	OwnerToken    string     `json:"owner_token,omitempty"`
	Listen        string     `json:"listen"`
	Provenance    Provenance `json:"provenance"`
	Queue         Queue      `json:"queue"`
	StartedAt     time.Time  `json:"started_at,omitempty"`
	UpdatedAt     time.Time  `json:"updated_at"`

	// WBHome and StatePath record *where* this daemon lives, so a reader can
	// tell "the daemon belonging to my home" from "a daemon answering on my
	// endpoint". They are empty in records written before schema 2, which is
	// reported as unknown home identity rather than assumed to match.
	WBHome    string `json:"wb_home,omitempty"`
	StatePath string `json:"state_path,omitempty"`

	// ProcessStartedAt is the recorded process's start time. PID alone is a
	// liveness coordinate that a recycled number can satisfy; the start time is
	// what makes "still running" a claim about *this* process. Zero means the
	// platform could not observe it, which is reported as unknown rather than
	// treated as a match.
	ProcessStartedAt time.Time `json:"process_started_at,omitempty"`

	// StoppedReason explains a stop the daemon did not choose — a runtime
	// directory removed underneath it, or an endpoint it could not bind. It is
	// recorded so the condition survives the process that hit it: a supervisor
	// restarts the daemon, and without this the reason would exist only in a
	// log the same removal may have unlinked.
	StoppedReason string `json:"stopped_reason,omitempty"`
}

State is private local state. It is never served by the dashboard API.

func NewStarting

func NewStarting(previous *State, listen string, provenance Provenance, ownerToken string, now time.Time) State

NewStarting creates the next fenced queue generation. Existing queue jobs stay in the durable queue file owned by the scheduler; this record tells the replacement scheduler exactly which binary owned the preceding generation.

func NewStartingAt added in v0.134.0

func NewStartingAt(previous *State, listen string, provenance Provenance, ownerToken, wbHome, statePath string, now time.Time) State

NewStartingAt is NewStarting with the daemon's own location recorded, so the generation it opens names the home it belongs to.

func (State) IsForeignHome added in v0.134.0

func (s State) IsForeignHome(currentHome string) (foreign bool, known bool)

IsForeignHome reports whether a record was written for a different WB home than the one this invocation resolves.

An empty recorded home means the record predates home identity. That is reported as unknown rather than as a match: claiming a record is ours because it failed to say otherwise is exactly how a daemon from an abandoned home gets presented as this machine's daemon.

func (*State) MarkDraining

func (s *State) MarkDraining(now time.Time)

func (*State) MarkReady

func (s *State) MarkReady(pid int, now time.Time)

func (*State) MarkReadyWithProcess added in v0.134.0

func (s *State) MarkReadyWithProcess(pid int, processStartedAt time.Time, now time.Time)

MarkReadyWithProcess records the process generation that is now serving. A zero processStartedAt records that the platform could not observe one.

func (*State) MarkStartingPID added in v0.127.1

func (s *State) MarkStartingPID(pid int, now time.Time)

func (*State) MarkStopped

func (s *State) MarkStopped(now time.Time)

func (*State) MarkStoppedWithReason added in v0.134.0

func (s *State) MarkStoppedWithReason(reason string, now time.Time)

MarkStoppedWithReason records a stop the daemon did not choose, keeping the reason readable after the process is gone.

func (State) ProcessGenerationMatches added in v0.134.0

func (s State) ProcessGenerationMatches(observedStart time.Time, observed bool) (match bool, known bool)

ProcessGenerationMatches reports whether the process now holding the recorded PID is the generation this record was written for.

The second result is whether the comparison was possible at all. A record with no recorded start time, or a platform that cannot observe one, yields known=false and leaves the caller to fall back to PID liveness and to say that it did. A recycled PID that *is* observable and differs is reported as a mismatch, because a confident "still running" about someone else's process is worse than an admitted unknown.

func (State) Valid

func (s State) Valid() error

type Status

type Status string
const (
	StatusStarting Status = "starting"
	StatusReady    Status = "ready"
	StatusDraining Status = "draining"
	StatusStopped  Status = "stopped"
)

type Store

type Store struct{ Path string }

Store reads and atomically replaces the local state record. Its directory and file permissions keep operation/queue metadata per-user on Unix; the Windows service adapter will use the current-user application-data ACL.

func (Store) Load

func (s Store) Load() (State, bool, error)

func (Store) Save

func (s Store) Save(state State) error

Jump to

Keyboard shortcuts

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