observe

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 22, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package observe is aa-server-status's observation layer: it answers "what is actually running" without ever killing or launching anything. See design/aa-server-status.md §6.1–§6.2 for the design this package implements.

Two concerns live here:

  • Identity: distinguishing a process aa-server-status itself spawned (an "our-child", for which the supervisor holds an *exec.Cmd handle) from a foreign process (matched only by PID + cmdline).
  • Listen-set gathering and classification: walking a server's whole process tree (e.g. a uvicorn parent plus its worker children, or an mlx launcher plus its subprocess) to build the *actual* set of listening TCP ports, then comparing it against the server's *declared* set ({port} ∪ listens, treated as exhaustive).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func SystemListenSet

func SystemListenSet() (map[int]int32, error)

SystemListenSet returns every TCP port currently in LISTEN state anywhere on the host, mapped to the PID holding it — a host-wide counterpart to ListenSet/TreeListenSet's single-process-tree scope. Used by teardown's post-kill verify step (design/aa-server-status.md §6.4): after a kill, the question is simply "is this port free," regardless of which process (if any) might hold it, so the check is not scoped to any one process tree. Like listeningPorts, this only ever counts LISTEN-state sockets — a lingering TIME_WAIT entry does not hold LISTEN and is correctly excluded.

Types

type Classification

type Classification int

Classification is the result of comparing a server's actual listen-set against its declared set ({port} ∪ listens, treated as exhaustive). See design/aa-server-status.md §6.2.

const (
	// CandidateUp: actual == declared. The final "serving" call belongs to
	// the health-probe module — this package only reports the port-level
	// match.
	CandidateUp Classification = iota
	// Partial: actual is a strict subset of declared — some declared ports
	// are not yet listening.
	Partial
	// StrayPort: actual contains a port outside the declared set — a loud
	// anomaly.
	StrayPort
)

func (Classification) String

func (c Classification) String() string

type Holder

type Holder struct {
	Port     int
	Identity Identity
}

Holder pairs a listening port with the Identity of the process holding it.

type Identity

type Identity struct {
	PID     int32
	Cmdline []string
	Ours    bool
}

Identity names a single OS process for observation purposes: its PID, its cmdline (used to match foreign processes), and whether aa-server-status holds the *exec.Cmd for it (an "our-child") or merely observed it externally.

func NewForeignIdentity

func NewForeignIdentity(pid int32) (*Identity, error)

NewForeignIdentity builds the Identity for an arbitrary PID that aa-server-status did not spawn, matched via its cmdline. It returns an error if the PID does not exist or its cmdline cannot be read.

func NewOursIdentity

func NewOursIdentity(cmd *exec.Cmd) (*Identity, error)

NewOursIdentity builds the Identity for a process aa-server-status itself spawned and holds a live handle for. cmd.Process must be non-nil (i.e. the command must already have been started).

type Result

type Result struct {
	Classification Classification
	// Declared is the input declared set, deduplicated.
	Declared []int
	// Actual is the set of ports actually found listening across the
	// server's process tree.
	Actual []int
	// Missing is Declared ports with no actual listener. Can be non-empty
	// even when Classification is StrayPort: a stray port and a missing
	// port are independent anomalies that may occur together, and StrayPort
	// takes priority in Classification as the louder one — check Missing
	// directly rather than assuming it is empty outside of Partial.
	Missing []int
	// Stray is Actual ports outside Declared (non-empty only for StrayPort;
	// unlike Missing, Stray is genuinely tied to that one Classification
	// value, since any non-empty Stray always makes Classification
	// StrayPort).
	Stray []int
	// ForeignHolders maps a declared port that IS actually listening, but
	// whose holder is not "ours", to that holder. This is what feeds the
	// `up` precondition gate and BLOCKED status rendering: a needed port
	// held by a process that isn't the server's own child must be
	// surfaced by PID + cmdline so the user can decide.
	ForeignHolders map[int]Identity
	// Degraded carries forward TreeObservation.Degraded: PIDs in the
	// observed tree whose ports or cmdline could not be read. A non-empty
	// Degraded means the exhaustive-set comparison above may be incomplete
	// — callers should treat the Classification with reduced confidence
	// rather than as a fully-confirmed verdict.
	Degraded []int32
}

Result is the outcome of classifying one server's observed state against its declared port set.

func Classify

func Classify(declared []int, obs TreeObservation) Result

Classify compares declared (the server's {port} ∪ listens, exhaustive) to obs (the observed listen-set across the whole process tree, as returned by TreeListenSet or ListenSet). Duplicate ports in declared are ignored.

  • actual ⊋ declared → StrayPort (loud anomaly): actual contains a port outside declared. Takes priority over Partial if both a missing declared port and a stray port are present simultaneously, since a stray port is the louder anomaly.
  • actual ⊊ declared → Partial: every actual port is declared, but at least one declared port has no listener yet.
  • actual == declared → CandidateUp.

type TreeObservation

type TreeObservation struct {
	Holders  map[int]Holder
	Degraded []int32
}

TreeObservation is the result of walking a process tree for its listen-set. Degraded lists PIDs discovered in the tree whose ports or cmdline could not be read (e.g. the process exited mid-walk, or a gopsutil call failed) — Result's declared-vs-actual comparison is computed only from what was successfully observed, so a non-empty Degraded means that comparison may be incomplete and callers should treat StrayPort/Partial verdicts on this observation with reduced confidence.

func ListenSet

func ListenSet(rootPID int32) (TreeObservation, error)

ListenSet returns the set of TCP ports the process tree rooted at rootPID is actually listening on — the root process plus every descendant (children, grandchildren, ...), so uvicorn workers or mlx subprocesses spawned under the root are included. Every Identity in the result has Ours=false; use TreeListenSet when the root (and its whole tree) should be marked as "ours".

func TreeListenSet

func TreeListenSet(rootPID int32) (TreeObservation, error)

TreeListenSet is like ListenSet, but marks every PID discovered under rootPID (the root itself plus all descendants) as "ours" in the returned Holders. Use this when rootPID is a process aa-server-status spawned, so that its whole tree (uvicorn workers, mlx subprocesses, etc.) is correctly identified as belonging to that server.

Jump to

Keyboard shortcuts

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