graphkit

package
v1.0.15 Latest Latest
Warning

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

Go to latest
Published: Nov 4, 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