Help us shape the future of Go! Take the 2026 Go Developer Survey

graphkit

package
v1.0.5 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
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

func (b *Builder) Build(root string, force func()) error

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

func (b *Builder) Built() []string

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

func (b *Builder) ReportTo(p Progress)

ReportTo sets where construction progress goes from now on; nil reports nowhere. Call it before Build.

func (*Builder) Sealed

func (b *Builder) Sealed() bool

Sealed reports whether Build has run.

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).

func (Plan) Names added in v1.0.0

func (p Plan) Names() []string

Names is every node, in construction order.

func (Plan) Start added in v1.0.0

func (p Plan) Start() []string

Start is the supervised nodes in the order Supervise starts them.

func (Plan) Stop added in v1.0.0

func (p Plan) Stop() []string

Stop is the supervised nodes in the order Supervise stops them: Start reversed, so the root's first field stops first and what it depends on after it.

type PlanNode added in v1.0.0

type PlanNode struct {
	Name  string
	Run   bool
	Drain bool
	Close bool
	Ready bool
}

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

func (n PlanNode) Supervised() bool

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

type Progress interface {
	Constructing(node string) (done func(err error))
}

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.

Jump to

Keyboard shortcuts

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