component

package
v0.0.0-...-9dc46f7 Latest Latest
Warning

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

Go to latest
Published: Dec 24, 2024 License: Apache-2.0 Imports: 12 Imported by: 14

Documentation

Overview

A framework for component lifecycle orchestration.

Each "component" is a subroutine with its own lifecycle. Components may depend on other components, which are initialized in topological order. If multiple components depend on the same component (using the component name as the equivalence class), the same instance of the component is used.

Concepts

`Args` is a runtime value used to customize a component for the caller's needs. It is mainly used for two purposes: (1) Distinguish between multiple instances of the same component type, e.g. two Kubernetes client sets connecting to two different clusters would be specified by a `ClusterName` field in the Args, which is included as part of its component name (thus the `name` function can accept `Args` as its argument). (2) Provide custom plugin implementations in the startup script, e.g. the `tracing.Observer` component is requested by specifying all observers implementations in Args in the main entrypoint, and just requested from other components without specifying the observer implementations; for this to work properly, the implementation-providing component request must precede all (direct and transitive) dependents of the component and still resolve to the same component name.

`Options` is a type that stores the data for the flags requested by each component. The `optionsFn` function registers flags into a given FlagSet, which are added to the global FlagSet using the component name as the prefix.

`Deps` is a type that stores the handles (`component.Dep[Api]`) for the dependency components it requested.

`State` stores the (possibly mutable) runtime states for the component. Data only need to be stored in `State` if they are to be used for lifecycle or component interactions.

`Api` is an external interface for dependents to interact with a dependency component. The actual value of `Api` should be a simple wrapper around the internal data (including the types above) that exposes abstract capabilities to downstream components.

The `init` function registers inter-component connections to prepare fthem for initialization. Since it is the first stage in the lifecycle that executes business logic, it is also the phase that constructs the `State`. A component `Api` is only considered fully usable after init is called. `init` is called in topological order of dependency, so `Api` of dependencies is considered fully usable in the init function as well.

Index

Constants

This section is empty.

Variables

View Source
var ErrRecursiveDependencies = errors.TagErrorf(
	"RecursiveDependencies",
	"recursive dependency chain",
)

Functions

func ApiFromMap

func ApiFromMap[Api any](apiMap ApiMap, name string) Api

Retrieves the interface to interact with a component of a known name.

func ApiOnly

func ApiOnly[Api any](name string, api Api) func(*DepRequests)

Provides a named component with a different implementation of its API. Used for mocking components in integration tests.

func RequireDep

func RequireDep[Api any](base Declared[Api]) func(*DepRequests)

Returns a closure that can be passed to `cmd.Run`.

func RequireDeps

func RequireDeps(deps ...func(*DepRequests)) func(*DepRequests)

Merges multiple `RequireDep` results into one.

Types

type ApiMap

type ApiMap map[string]any

Accessor to interact with components by name. Use ApiFromMap to get the actual interfaces.

func NamedComponentsToApiMap

func NamedComponentsToApiMap(components []NamedComponent) ApiMap

Converts a NamedComponent slice to an ApiMap.

type Component

type Component interface {

	// Registers flags for this component.
	AddFlags(fs *flag.FlagSet)
	// Registers inter-component connections.
	//
	// Should not interact with the environment or start any background tasks.
	// The context may be removed in the future; background tasks should use the context from Start instead.
	Init(ctx context.Context) error
	// Starts the actual work.
	Start(ctx context.Context) error
	// Waits for the component to shut down gracefully.
	// Should return when ctx expires.
	Join(ctx context.Context) error
	// Registers health check handlers.
	RegisterHealthChecks(handler *healthz.Handler, onFail func(name string, err error))
	// contains filtered or unexported methods
}

Controls the lifecycle of a component.

This interface is only useful for lifecycle orchestration and should not be implemented by other packages.

type Data

type Data[Args any, Options any, Deps any, State any] struct {
	// Runtime arguments for this component,
	// typically used to differentiate between multiple instances of the same type.
	Args Args

	// Resolved flags for the component.
	//
	// Initialized after newOptions is called.
	Options Options

	// Dependency handles for the component.
	//
	// Initialized after newDeps is called.
	Deps Deps

	// Runtime states for the component.
	//
	// Initialized after init is called.
	State *State
}

Stores various data related to a component.

type Declared

type Declared[Api any] interface {

	// Constructs a new instance of the raw component without dependency deduplication.
	GetNew() (Component, func() Api)
	// contains filtered or unexported methods
}

type DeclaredCtor

type DeclaredCtor[Args any, Deps any, Api any] func(Args) Declared[Api]

func Declare

func Declare[Args any, Options any, Deps any, State any, Api any](
	name func(args Args) string,
	newOptions func(args Args, fs *flag.FlagSet) Options,
	newDeps func(args Args, requests *DepRequests) Deps,
	init func(ctx context.Context, args Args, options Options, deps Deps) (*State, error),
	lifecycle Lifecycle[Args, Options, Deps, State],
	api func(d *Data[Args, Options, Deps, State]) Api,
) DeclaredCtor[Args, Deps, Api]

Declares a generic component. Returns a constructor for Declared that actually instantiates the component request.

This function is typically used to assign a global variable to act like a function:

var New = component.Declare(...)

Refer to package documentation for the description of the arguments.

func (DeclaredCtor[Args, Deps, Api]) WithMergeFn

func (ctor DeclaredCtor[Args, Deps, Api]) WithMergeFn(
	onMerge func(*Args, *Deps, *DepRequests),
) DeclaredCtor[Args, Deps, Api]

type Dep

type Dep[Api any] interface {
	// Returns the interface to work with a component.
	//
	// The return value may differ before startup completion.
	// Do not use the result of .Get() called during init in the main lifecycle.
	Get() Api
}

A dependency handle.

func DepPtr

func DepPtr[Api any](requests *DepRequests, base Declared[Api]) Dep[Api]

Requests a dependency, returning a handle to interact with the dependency.

type DepRequests

type DepRequests struct {
	// contains filtered or unexported fields
}

A registry of dependencies requested by components.

type HealthChecks

type HealthChecks map[string]func() error

A map of health checks, where each non-nil function returns nil for ready status and returns a non-nil error for unready status.

type Lifecycle

type Lifecycle[Args any, Options any, Deps any, State any] struct {
	// Starts the background tasks of a component.
	//
	// `ctx` is canceled when the process starts terminating.
	// All public fields in `state` are available for use.
	Start func(ctx context.Context, args *Args, options *Options, deps *Deps, state *State) error

	// Waits for the component to shut down gracefully.
	//
	// `ctx` is canceled after graceful shutdown times out.
	// All public fields in `state` are available for use.
	Join func(ctx context.Context, args *Args, options *Options, deps *Deps, state *State) error

	// Defines health checks for this component.
	HealthChecks func(*State) HealthChecks
}

Lifecycle hooks for a component.

The zero value (nil functions) is a valid default.

type NamedComponent

type NamedComponent struct {
	Component Component
	Name      string
	// contains filtered or unexported fields
}

Exposes the lifecycle and interaction interface of a component, used for component orchestration.

func ResolveList

func ResolveList(requestFns []func(*DepRequests)) []NamedComponent

Returns a slice of components with all dependencies resolved and in initialization order.

Jump to

Keyboard shortcuts

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