container

package
v3.13.0 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2026 License: MIT Imports: 14 Imported by: 1

Documentation

Overview

Package container provides the dependency-injection container, scopes, service factories, and lifecycle.

Index

Constants

This section is empty.

Variables

View Source
var ErrServiceIdAlreadyRegistered = errors.New("service already registered")

ErrServiceIdAlreadyRegistered is the cause of a Register refusal for a duplicate service name; classify with errors.Is so callers (the application boot collision report) can tell a duplicate apart from other registration failures.

View Source
var ErrServiceTypeAlreadyRegistered = errors.New("service type already registered")

ErrServiceTypeAlreadyRegistered is the cause of a strict type-registration refusal for a duplicate service type.

Functions

func AllImplementing added in v3.12.0

func AllImplementing[T any](resolver containercontract.Resolver) ([]T, error)
AllImplementing resolves every registered service that satisfies the interface T: every type registration whose type implements it — one registered under the interface type itself included — and every instance of a type registered under several names, in an order that never changes between runs (descending WithCollectionPriority, then type and name). A component that has to act on all of a kind — dispatching to every message handler, scheduling every cron task — collects them here instead of being handed a list assembled by hand, which is the list that goes stale when a service is added.

The services are resolved by their registered names through the resolver handed in, so a collection gathered on a request scope yields the scope's overrides. The service whose provider is doing the collecting is excluded instead of failing the collection: the composite dispatcher that is itself one of the handlers it dispatches to collects the others, the way a tagged iterator excludes its referencing service. Only that innermost service is excluded — a deeper service on the same resolution path stays in the collection and fails as the circular dependency it is, since excluding it would freeze a collection whose content depends on which service happened to boot first.

It resolves the services it finds, so a provider that fails aborts the collection rather than yielding a partial set. Collect with the resolver the provider receives, never with the container itself: a container blocks on its own in-flight creation the way every container Get does, so handing it to a provider that is part of the collection waits on itself. A closed scope refuses the collection the way its Get refuses, rather than dispatching to a silently empty set.

func FromResolver

func FromResolver[T any](resolver containercontract.Resolver, serviceName string) (T, error)

func FromResolverByType

func FromResolverByType[T any](resolver containercontract.Resolver) (T, error)

func MustAllImplementing added in v3.12.0

func MustAllImplementing[T any](resolver containercontract.Resolver) []T

func MustFromResolver

func MustFromResolver[T any](resolver containercontract.Resolver, serviceName string) T

func MustFromResolverByType

func MustFromResolverByType[T any](resolver containercontract.Resolver) T

func MustRegister

func MustRegister[T any](
	registrar containercontract.Registrar,
	serviceName string,
	provider containercontract.Provider[T],
	options ...containercontract.RegisterOption,
)

func MustRegisterType

func MustRegisterType[T any](
	registrar containercontract.Registrar,
	provider containercontract.Provider[T],
	options ...containercontract.RegisterOption,
)

func NewContainer

func NewContainer() containercontract.Container

func Register

func Register[T any](
	registrar containercontract.Registrar,
	serviceName string,
	provider containercontract.Provider[T],
	options ...containercontract.RegisterOption,
) error

func RegisterType

func RegisterType[T any](
	registrar containercontract.Registrar,
	provider containercontract.Provider[T],
	options ...containercontract.RegisterOption,
) error

func WithCollectionPriority added in v3.12.0

func WithCollectionPriority(priority int) containercontract.RegisterOption

WithCollectionPriority orders the registration inside AllImplementing collections: a higher priority is collected — and therefore dispatched by whatever consumes the collection — earlier. The unset priority is zero, so a negative one sorts after every service that declared nothing; registrations sharing a priority keep the stable type-and-name order, so adding a priority to one service never reshuffles the rest. Only a type-registered service can be collected, so the option is meaningless together with WithoutTypeRegistration.

func WithTypeRegistration

func WithTypeRegistration(isStrict bool) containercontract.RegisterOption

func WithoutTypeRegistration

func WithoutTypeRegistration() containercontract.RegisterOption

Types

type LazyService added in v3.11.0

type LazyService[T any] struct {
	// contains filtered or unexported fields
}

LazyService defers resolving a container service until its first use and memoizes success only — a failed or nil resolution is retried on the next call, mirroring the container's own resolver. A component assembled during the boot phase — a cli command, an http middleware — can hold a service whose provider is registered but not yet safe to resolve at that phase, without hand-rolling a deferred-resolution proxy for each one. A genuinely app-specific proxy over the app's own interface is still built on this handle; the framework ships the proxies over its own contracts (for example lock.NewLazyLocker).

func Lazy added in v3.11.0

func Lazy[T any](resolver containercontract.Resolver, serviceName string) *LazyService[T]
Lazy returns a handle that resolves serviceName from the resolver on first use, the deferred form of FromResolver / MustFromResolver.

Build the handle over the container (or a resolver not shared across goroutines): every container resolution mints a fresh resolver context, so concurrent first uses are safe. A handle that captures the resolver context a provider was handed and then escapes that provider must not have Get/Resolve called from several goroutines at once — that context is a single resolution chain and is not safe for concurrent use.

func LazyByType added in v3.11.0

func LazyByType[T any](resolver containercontract.Resolver) *LazyService[T]

LazyByType returns a handle that resolves the service by its type on first use, the deferred form of FromResolverByType / MustFromResolverByType.

func (*LazyService[T]) Get added in v3.11.0

func (instance *LazyService[T]) Get() T

Get resolves the service and returns the memoized value once a resolution has succeeded, panicking if the resolution fails or yields nil — the deferred equivalent of MustFromResolver; because neither a failure nor a nil yield is memoized, the next call retries the resolution.

func (*LazyService[T]) Resolve added in v3.11.0

func (instance *LazyService[T]) Resolve() (T, error)

Resolve resolves the service and memoizes success only: a successfully resolved non-nil value is returned on every later call without re-running the resolver, while a failed resolution returns the error without memoizing it and a nil yield is likewise passed through unmemoized, so the next call retries either — a transient outage at first use does not poison the handle; use Get for the panic-on-failure path. The resolver runs outside the handle's lock, so a resolver that reaches back into this same handle does not deadlock against the handle's own synchronization: given a handle built over a live resolver context, the re-entry reaches the container's cycle detection and surfaces as a circular-dependency error. A handle built over the container itself (the resolver argument being the container rather than a provider's resolver context) is a different matter — every container.Get mints a fresh resolution context, so a re-entrant chain through such a handle blocks on the container's own creation wait rather than being reported as a cycle; that is a property of the container's resolution, not of this handle, and it is unchanged by the lock scope. When several first uses race, each may run the resolver and the first to store wins; the container's own memoization makes the duplicates converge for shared services.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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