golazy.dev golazy.dev / lazycontrolplane Index | Files

package lazycontrolplane

import "golazy.dev/lazycontrolplane"

Package lazycontrolplane provides operational HTTP endpoints for GoLazy applications.

Most applications compose the package through lazyapp:

app := lazyapp.New(lazyapp.Config{
	ControlPlane: lazycontrolplane.Config{
		Readiness: []lazycontrolplane.ReadinessCheck{{
			Name:  "database",
			Check: databaseReady,
		}},
	},
})

Direct users can register owned endpoints before sealing and serving the standalone handler:

plane := lazycontrolplane.New(lazycontrolplane.Config{})
err := plane.Register(lazycontrolplane.Endpoint{
	ID:          "example.com/myapp/build",
	Owner:       "example.com/myapp",
	Pattern:     "GET /build",
	Description: "Application build information",
	Handler:     buildHandler,
})
if err != nil {
	return err
}
plane.Seal()
return http.ListenAndServe(":2001", plane.StandaloneHandler())

A control plane owns framework and operations routes that should not be part of the application's route table. The zero Config is useful: it creates GET /livez, GET /readyz, and the empty developer-panel discovery document at GET /_golazy/panels. /livez reports that the process can answer HTTP requests. /readyz runs configured ReadinessCheck functions and returns 503 Service Unavailable when any dependency or runtime state says the app is not ready to receive traffic.

The package can be used directly with net/http, but most applications pass a Config or *ControlPlane to lazyapp.Config.ControlPlane. lazyapp builds the control plane, adds package-owned endpoints for configured jobs and telemetry, and, when built with the lazydev tag, registers development control endpoints from packages such as lazyassets, lazybuildinfo, lazycache, lazycontroller, lazydeps, lazyjobs, lazyroutes, and lazytelemetry.

lazyapp decides where the plane is served. In production builds it does not intercept application requests unless CONTROL_PLANE_ADDR is set to the same listen address as the app. When CONTROL_PLANE_ADDR points at a different address, lazyapp serves ControlPlane.StandaloneHandler on that listener; the standalone handler adds a small root index and keeps application "/" routes separate. In lazydev builds, lazyapp keeps the control plane available on the app handler so the development panel can call it.

Owned operational endpoints, including endpoints contributed by add-ons, can be registered with ControlPlane.Register. Registration records a stable ID, owner, pattern, and description for duplicate detection and the standalone endpoint index. RegisterReadinessCheck provides the matching error-returning readiness API. Registrations are concurrency-safe, including while an early startup control plane is serving, and are closed explicitly with ControlPlane.Seal after application setup is complete.

ControlPlane.Handle and ControlPlane.AddReadinessCheck remain available as panic-on-error compatibility APIs. Use Config.Metrics or a custom handler for /metrics, and use Config.Pprof or ControlPlane.EnablePprof to attach the standard net/http/pprof handlers.

Constants

const PanelsPath

PanelsPath is the control-plane discovery endpoint for developer-panel contributions registered by the running application and its add-ons.

const PanelsPath = "/_golazy/panels"

Variables

var ErrSealed

ErrSealed is returned when code tries to extend a control plane that has already been prepared for serving.

var ErrSealed = errors.New("lazycontrolplane: registrations are sealed")

Types

type Builder

Builder creates a control plane for lazyapp.

Config and *ControlPlane implement Builder. This keeps lazyapp.Config's ControlPlane field optional while still allowing ControlPlane: Config{}.

type Builder interface {
	BuildControlPlane() *ControlPlane
}

type ControlPlane

ControlPlane routes operational endpoints.

type ControlPlane struct {
	// contains filtered or unexported fields
}
func New

New builds a control plane from config.

func New(config Config) *ControlPlane
func (plane *ControlPlane) AddReadinessCheck

AddReadinessCheck appends a readiness check to /readyz.

AddReadinessCheck is the compatibility API. New integrations should use RegisterReadinessCheck so validation errors can be handled by the caller.

func (plane *ControlPlane) AddReadinessCheck(check ReadinessCheck)
func (plane *ControlPlane) BuildControlPlane

BuildControlPlane implements Builder.

func (plane *ControlPlane) BuildControlPlane() *ControlPlane
func (plane *ControlPlane) EnablePprof

EnablePprof registers the standard net/http/pprof handlers.

It is safe to call EnablePprof more than once.

func (plane *ControlPlane) EnablePprof()
func (plane *ControlPlane) Endpoints

Endpoints returns a deterministic snapshot of registered endpoint metadata.

func (plane *ControlPlane) Endpoints() []EndpointInfo
func (plane *ControlPlane) Handle

Handle registers an exact control-plane endpoint.

Handle is the compatibility API for registrations without ownership metadata. New integrations should use Register so validation errors can be handled by the caller.

func (plane *ControlPlane) Handle(pattern string, handler http.Handler)
func (plane *ControlPlane) Handler

Handler mounts the control plane in front of next.

func (plane *ControlPlane) Handler(next http.Handler) http.Handler
func (plane *ControlPlane) HandlesPath

HandlesPath reports whether path belongs to the control plane.

func (plane *ControlPlane) HandlesPath(path string) bool
func (plane *ControlPlane) Panels

Panels returns a deterministic snapshot of registered developer-panel entries. Lower Order values sort first, followed by title and stable ID.

func (plane *ControlPlane) Panels() []PanelInfo
func (plane *ControlPlane) Register

Register adds an owned endpoint to the control plane.

Registration is concurrency-safe. It fails when ID or Pattern is already registered, when the endpoint is invalid, or after the control plane has been sealed for serving.

func (plane *ControlPlane) Register(endpoint Endpoint) error
func (plane *ControlPlane) RegisterPanel

RegisterPanel adds a developer-panel entry backed by an endpoint registered on this control plane. The endpoint must belong to the same owner, support GET requests, and use an exact path. Prefix and wildcard patterns are rejected so a panel host cannot proxy into another endpoint's namespace.

func (plane *ControlPlane) RegisterPanel(panel Panel) error
func (plane *ControlPlane) RegisterReadinessCheck

RegisterReadinessCheck appends a readiness check to /readyz.

func (plane *ControlPlane) RegisterReadinessCheck(check ReadinessCheck) error
func (plane *ControlPlane) Seal

Seal closes endpoint and readiness registration. It is safe to call Seal more than once. The application lifecycle calls Seal once all package and add-on registrations are complete.

func (plane *ControlPlane) Seal()
func (plane *ControlPlane) ServeHTTP

ServeHTTP serves control-plane endpoints.

func (plane *ControlPlane) ServeHTTP(w http.ResponseWriter, r *http.Request)
func (plane *ControlPlane) StandaloneHandler

StandaloneHandler serves the control plane on its own listener.

It adds a root HTML index that lists registered endpoints. Use Handler when the control plane shares an application listener so "/" stays owned by the app.

func (plane *ControlPlane) StandaloneHandler() http.Handler

type Endpoint

Endpoint describes an owned control-plane endpoint.

ID must be unique within a control plane. Owner identifies the framework package, application, or add-on responsible for the endpoint. Pattern uses net/http ServeMux syntax.

type Endpoint struct {
	ID		string
	Owner		string
	Pattern		string
	Description	string
	Handler		http.Handler
}

type EndpointInfo

EndpointInfo is the public, handler-free description of a registered endpoint.

type EndpointInfo struct {
	ID		string
	Owner		string
	Pattern		string
	Description	string
	Method		string
	Path		string
	Prefix		bool
}

type Panel

Panel describes one developer-panel entry backed by an owned control-plane endpoint. EndpointID must name a GET-capable endpoint registered by the same Owner. Actions may reference exact POST-only endpoints owned by that Owner. The endpoint handlers continue to run in the application process; panel hosts consume only the metadata returned by PanelsPath.

type Panel struct {
	ID		string
	Owner		string
	Title		string
	Description	string
	EndpointID	string
	Actions		[]PanelAction
	Order		int
}

type PanelAction

PanelAction describes a trusted action rendered by a developer-panel host. EndpointID must name an exact POST endpoint registered by the panel Owner. Add-on content cannot submit this endpoint directly; the host resolves the stable panel and action IDs from discovery before issuing an empty POST.

type PanelAction struct {
	ID		string
	Title		string
	Description	string
	EndpointID	string
}

type PanelActionInfo

PanelActionInfo is the resolved, handler-free action metadata exposed to developer-panel hosts.

type PanelActionInfo struct {
	ID		string	`json:"id"`
	Title		string	`json:"title"`
	Description	string	`json:"description"`
	EndpointID	string	`json:"endpoint_id"`
	Pattern		string	`json:"pattern"`
	Method		string	`json:"method"`
	Path		string	`json:"path"`
}

type PanelInfo

PanelInfo is the resolved, handler-free description exposed to developer panel hosts.

type PanelInfo struct {
	ID		string			`json:"id"`
	Owner		string			`json:"owner"`
	Title		string			`json:"title"`
	Description	string			`json:"description"`
	EndpointID	string			`json:"endpoint_id"`
	Pattern		string			`json:"pattern"`
	Method		string			`json:"method"`
	Path		string			`json:"path"`
	Actions		[]PanelActionInfo	`json:"actions,omitempty"`
	Order		int			`json:"order"`
}

type Registrar

Registrar accepts owned endpoints and readiness checks during control-plane setup. Applications close registration explicitly with ControlPlane.Seal after startup packages and add-ons finish registering.

type Registrar interface {
	Register(Endpoint) error
	RegisterReadinessCheck(ReadinessCheck) error
	RegisterPanel(Panel) error
}