Documentation
¶
Overview ¶
Package graphkit is the runtime under a project's generated composition graph (internal/app/graph_gen.go): memoized construction of each node, the root's Build — force the closure, then seal — and the lifecycle nodes of what was built, in the order it was built, for lifecyclekit.Supervise.
The graph itself is generated Go. Every edge is a value expression in the project's internal/app/compose.go, and every accessor is a typed method on the project's *app.Graph that calls Get. Nothing here resolves a dependency, looks a value up by name, or inspects a type: which node a Deps field gets was decided at generate time, and which lifecycle methods a node has was read off its type by the generator and handed to Get as a Node literal.
func (g *Graph) Billing() *billing.Service {
return graphkit.Get(&g.b, &g.m.Billing, "billing", g.newBilling, nil)
}
Construction is eager within a root and fails loud at boot: Build forces the root's whole closure before anything runs, a construction error unwinds with the path that reached it ("build server: api_listener → user_routes → billing: …"), and once the graph is sealed an accessor for a node the root never reached panics instead of constructing it on a first request.
While it builds, a Builder reports each node's construction to a Progress (ReportTo) — in a generated graph, the boot probes, so /readyz names the node whose constructor is blocking boot.
A Builder is used from one goroutine while it builds. After Build, reading an already-built node is safe from any goroutine.
Index ¶
- Variables
- func Catch(f func()) (err error)
- func Get[T any](b *Builder, m *Memo[T], name string, ctor func() (T, error), ...) T
- type Builder
- func (b *Builder) Build(root string, force func()) error
- func (b *Builder) Built() []string
- func (b *Builder) Nodes() []lifecyclekit.Node
- func (b *Builder) ReportTo(p Progress)
- func (b *Builder) Sealed() bool
- func (b *Builder) Supervise(ctx context.Context, policy lifecyclekit.Policy, probes *serverkit.Probes, ...) error
- type Memo
- type Plan
- type PlanNode
- type Progress
Constants ¶
This section is empty.
Variables ¶
var ErrSealed = errors.New("graphkit: the graph is sealed")
ErrSealed is the cause of the panic an accessor raises for a node the root's Build did not construct.
Functions ¶
func Catch ¶
func Catch(f func()) (err error)
Catch runs f and returns the construction error a node's accessor panicked with, for a caller that uses the graph's accessors outside Build. Any other panic is re-raised.
func Get ¶
func Get[T any](b *Builder, m *Memo[T], name string, ctor func() (T, error), node func(T) lifecyclekit.Node) T
Get returns the node m memoizes, constructing it with ctor the first time. name labels it in errors and in the supervisor's logs. node, when non-nil, is the node's lifecycle — its Run, Drain, Close and Ready methods, read off its type at generate time; a Node with none of them is not supervised.
A construction error does not return: it panics, carrying the path of nodes that reached it, and Build recovers it. Calling an accessor outside Build (a hand-written main using the graph unsealed) gets the same panic; Catch turns it into an error.
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder is one graph's construction state. The zero value is ready to use.
func (*Builder) Build ¶
Build constructs a root: force calls the root's field accessors, so every node the root reaches is constructed once, dependencies first. Build then seals the graph. A construction error comes back as "build <root>: a → b → c: <cause>". Building a second root on a sealed graph is an error: one process runs one root.
func (*Builder) Built ¶
Built is the name of every constructed node, in construction-completion order: each after everything it depends on.
func (*Builder) Nodes ¶
func (b *Builder) Nodes() []lifecyclekit.Node
Nodes are the lifecycle nodes of every constructed node that has a Run, Drain, Close or Ready, in construction order — the order Supervise starts them in, so a node starts after everything it depends on and stops before.
func (*Builder) ReportTo ¶ added in v1.0.0
ReportTo sets where construction progress goes from now on; nil reports nowhere. Call it before Build.
func (*Builder) Supervise ¶
func (b *Builder) Supervise(ctx context.Context, policy lifecyclekit.Policy, probes *serverkit.Probes, first ...lifecyclekit.Node) error
Supervise runs the built nodes under lifecyclekit.Supervise until ctx ends. Every node that reports Ready joins probes' /readyz, and probes' Drainer is the policy's readiness gate and shutdown budget when the policy names none. probes may be nil — a root with no probe route. Call it after Build.
first are nodes the graph did not build — a root's probe listener — that start before every built node and stop after all of them, so they answer for the whole of boot and drain.
type Memo ¶
type Memo[T any] struct { // contains filtered or unexported fields }
Memo holds one node's value once it is constructed. The zero value is an unbuilt node.
type Plan ¶ added in v1.0.0
type Plan []PlanNode
Plan is a root's nodes in the order its Build constructs them — each after everything it depends on, the root's last field first — preceded, for a root none of whose nodes serves the probes, by the probe listener Run starts before every node and stops after them.
It is the plan, not a record: a node whose constructor returns a nil value at run time is not supervised, and Built() names only what a real Build constructed (never the probe listener).
type PlanNode ¶ added in v1.0.0
PlanNode is one node of a root's plan: its name — the name Built and the supervisor's "drain:" lines use — and which lifecycle methods its type has, read off the type when graph_gen.go was generated.
func (PlanNode) Supervised ¶ added in v1.0.0
Supervised reports whether Supervise runs the node: it has a Run, Drain, Close or Ready. A node without one is constructed and never started or stopped.
type Progress ¶ added in v1.0.0
Progress is told about each node's construction as it happens: Constructing as a node's constructor starts, and the done it returns as that constructor ends — with its error, nil once the node is built. Nodes nest: a node's dependencies start and end inside it, so the latest started and not yet done is the constructor actually running. A dependency's failure ends every node that reached it, each with that error. Construction is sequential: one goroutine, one node's constructor at a time.
serverkit's boot probes satisfy it, so a root's /readyz names the node boot is waiting on.