Documentation
¶
Overview ¶
Package host is MicroJet's application orchestrator: a fluent builder with a dependency-injection container, composable modules, background workers, and a managed lifecycle with graceful shutdown.
Index ¶
- Constants
- Variables
- func MustResolveService[T any](a *App, name ...string) T
- func ProvideService[T any](a *App, service T, name ...string)
- func ResolveAllServices[T any](a *App) map[string]T
- func ResolveService[T any](a *App, name ...string) (T, bool)
- func ResolveServiceBy[T any](a *App, pred func(T) bool) (T, bool)
- func WaitForExitSignal()
- type App
- func (a *App) Close()
- func (a *App) Configure(cfgs ...configx.Configurable) *App
- func (a *App) Err() error
- func (a *App) InitServices() *App
- func (a *App) MustRun()
- func (a *App) ProvideKey(key string, value any) *App
- func (a *App) RangeServices(fn func(service any) bool)
- func (a *App) ResolveKey(key string) (any, bool)
- func (a *App) Run() error
- func (a *App) Setup(handler ...HandlerFunc) *App
- func (a *App) Shutdown(ctx context.Context) error
- func (a *App) Start(ctx context.Context) error
- func (a *App) Wait() error
- func (a *App) WithModule(m Module) *App
- func (a *App) WithModules(mods ...Module) *App
- func (a *App) WithPeriodicWorker(name string, interval time.Duration, ...) *App
- func (a *App) WithProvider(fn HandlerFunc) *App
- func (a *App) WithWorker(name string, fn func(ctx context.Context, app *App) error) *App
- type AppConfig
- type AsyncWorker
- type CloseOrderer
- type Config
- type ErrSource
- type HandlerFunc
- type KeyedModule
- type Module
- type ModuleFunc
- type NamedModule
- type Option
- type PeriodicWorker
- type ServiceCloser
- type ServiceIniter
- type ServiceSetupper
- type ServiceStarter
Constants ¶
const ( EnvTest = "test" EnvDevelopment = "development" EnvProduction = "production" )
const ( // CloseEdge closes first: inbound traffic sources that must stop accepting and // drain, such as HTTP servers and message subscribers. CloseEdge = 0 // CloseDefault is the order for services that do not implement CloseOrderer — // ordinary application services. CloseDefault = 50 // CloseBackend closes last: shared resources others depend on during their own // shutdown, such as databases, caches, the message broker, and tracing. CloseBackend = 100 )
Close ordering bands. Services are closed in ascending order, so inbound "edges" stop accepting work and drain before the "backends" they depend on are torn down — e.g. an HTTP server finishes serving in-flight requests while its database is still open. Services that do not implement CloseOrderer close at CloseDefault. The values are plain ints, so a service needing finer control can return any value between or beyond these (lower = earlier).
Within a single band, services close in reverse registration order — the last one registered closes first — mirroring construction so a service tears down before the ones it was built on top of.
Variables ¶
var ErrServiceNotRegistered = errorx.NewInternalError("General", "Service is not registered")
Functions ¶
func MustResolveService ¶
MustResolveService returns the service for type T (and optional name), panicking if none is registered.
func ProvideService ¶
ProvideService registers service in the container under its type T and an optional name. Re-providing the same (type, name) replaces the earlier value; distinct names register side by side.
func ResolveAllServices ¶ added in v0.28.0
ResolveAllServices returns every service registered under type T, keyed by the name it was provided with ("" for the default, unnamed instance). Use it to enumerate all implementors of an interface — registered side by side under one interface type via distinct names — and pick one by a runtime criterion:
host.ProvideService[Notifier](a, email, "email")
host.ProvideService[Notifier](a, sms, "sms")
for name, n := range host.ResolveAllServices[Notifier](a) { ... }
Only services registered under T itself are returned; an instance registered under a concrete type is not discoverable through its interface. The result is a fresh map (never nil) and safe to mutate.
func ResolveService ¶
ResolveService returns the service registered for type T and the optional name, reporting whether one was found.
func ResolveServiceBy ¶ added in v0.28.0
ResolveServiceBy returns the first service registered under type T that satisfies pred, reporting whether one matched. Iteration order is unspecified, so pred should identify at most one service (or the caller must not depend on which match wins). It is a convenience over ResolveAllServices for criteria- based selection:
h, ok := host.ResolveServiceBy[Handler](a, func(h Handler) bool {
return h.CanHandle(contentType)
})
func WaitForExitSignal ¶
func WaitForExitSignal()
WaitForExitSignal blocks until the process receives SIGINT or SIGTERM.
Types ¶
type App ¶
type App struct {
Config *Config
Logger *slog.Logger
Clock core.TimeProvider
// contains filtered or unexported fields
}
App is the central runtime object for a service. Build it with the fluent New().With*() chain at service startup.
func New ¶
New constructs an App, loading the standard configuration sections and the logger. Returns an error instead of panicking so callers can handle config failures gracefully. To load service-specific config sections call app.Configure after construction.
func (*App) Close ¶
func (a *App) Close()
Close gracefully shuts down all managed resources. Safe to call more than once.
func (*App) Configure ¶ added in v0.11.0
func (a *App) Configure(cfgs ...configx.Configurable) *App
Configure calls ReadConfig on each Configurable using the app's shared config reader, so the config file is only parsed once. Call this right after New() to populate service-specific config structs before starting services.
func (*App) Err ¶
Err returns the first error recorded while building the App via the fluent With*/Setup methods, or nil if the chain succeeded.
func (*App) InitServices ¶
func (*App) MustRun ¶
func (a *App) MustRun()
MustRun is like Run but logs and exits the process on error.
func (*App) ProvideKey ¶
ProvideKey stores an arbitrary value under a string key — an escape hatch for values not identified by Go type. Prefer ProvideService for services.
func (*App) RangeServices ¶ added in v0.19.0
RangeServices calls fn for each registered service until fn returns false. Iteration order is unspecified — callers must not depend on it, even though it happens to follow registration order today. It lets satellite packages and modules inspect the container — e.g. aggregate health checks across services — without needing access to its internals.
func (*App) ResolveKey ¶
ResolveKey returns the value stored under a string key by ProvideKey.
func (*App) Run ¶
Run initializes services, starts workers and the HTTP server (if configured), then blocks until a termination signal or fatal server error. On exit it cancels workers, waits for them, and gracefully shuts down.
func (*App) Setup ¶
func (a *App) Setup(handler ...HandlerFunc) *App
Setup queues a setup handler (e.g. migrations or route registration). Handlers run after services are initialized — so connected resources (databases, caches, brokers) are available — but before the HTTP server starts serving. Within the chain they run in registration order. If services are already initialized (the manual InitServices path) the handler runs immediately. Errors are deferred and surfaced by Run/MustRun/Err.
func (*App) Shutdown ¶ added in v0.31.0
Shutdown gracefully stops the app: it unblocks Wait, flips readiness to not-ready, waits the configured drain delay (App.ShutdownDelay), cancels the workers, waits for them, and closes services. The ctx deadline bounds the drain and the wait for workers — cutting a slow drain or a stuck worker short — in addition to the WithCloseTimeout that bounds Close. It returns ctx.Err() if the ctx expired before the workers stopped, otherwise nil. Safe to call more than once; later calls return the first outcome without re-running.
func (*App) Start ¶ added in v0.31.0
Start brings the app fully up — init, setup, start, workers — without blocking. The supplied ctx becomes the root of the app's worker context; cancelling it begins graceful shutdown, which Wait observes. Start runs the same phases as Run and wraps their errors identically ("initializing services: ...", etc.), closing the app if a phase fails. It is guarded, so calling it more than once is a no-op that returns the original result.
Use Start with Wait and Shutdown to embed an App in a process that already owns cancellation — a monolith, CLI, test, or supervisor — where Run's built-in signal handling and blocking are not wanted.
func (*App) Wait ¶ added in v0.31.0
Wait blocks until the app begins stopping: the Start context is cancelled, a service's background loop exits (an ErrSource delivery), or Shutdown is called. It returns the fatal service error, if any — nil for a context-cancellation or Shutdown-initiated stop. Repeated calls return the same value. Wait does not itself stop the app; pair it with Shutdown.
func (*App) WithModule ¶ added in v0.10.0
WithModule installs a module, running its Register hook. Struct modules are deduplicated so a shared module imported by several parents (the "diamond" case) installs exactly once; the dedup key is the module's ModuleKey if it implements KeyedModule, otherwise its Go type. ModuleFunc values are anonymous and never deduplicated. Errors are deferred to Run/MustRun/Err.
func (*App) WithModules ¶ added in v0.10.0
WithModules installs several modules in order, short-circuiting on the first error like the rest of the fluent chain.
func (*App) WithPeriodicWorker ¶
func (a *App) WithPeriodicWorker(name string, interval time.Duration, fn func(ctx context.Context, app *App) error) *App
WithPeriodicWorker registers a worker that calls fn immediately on start, then waits interval before calling again. The next tick never starts until the previous call has returned.
func (*App) WithProvider ¶
func (a *App) WithProvider(fn HandlerFunc) *App
WithProvider runs fn to register services imperatively within the fluent chain, deferring any error to Run/MustRun/Err.
type AppConfig ¶ added in v0.4.0
type AppConfig struct {
Namespace string `mapstructure:"namespace"`
Environment string `mapstructure:"environment"`
Name string `mapstructure:"name"`
Version string `mapstructure:"version"`
Debug bool `mapstructure:"debug"`
// ShutdownDelay is how long the host waits after flipping readiness to
// not-ready before it cancels workers and closes services. Defaults to 0
// (flip and continue immediately). On Kubernetes set it to roughly the pod's
// terminationGracePeriodSeconds headroom (e.g. "5s") so kube-proxy removes the
// pod from its endpoints before in-flight requests are drained.
ShutdownDelay time.Duration `mapstructure:"shutdownDelay"`
}
func (*AppConfig) GetEnvironment ¶ added in v0.4.0
func (*AppConfig) IsDevelopment ¶ added in v0.4.0
func (*AppConfig) IsProduction ¶ added in v0.4.0
type AsyncWorker ¶
AsyncWorker is implemented by DI-registered services that should run as a background goroutine. Run is called in a goroutine and should block until ctx is cancelled.
type CloseOrderer ¶ added in v0.19.0
type CloseOrderer interface {
CloseOrder() int
}
CloseOrderer lets a service control when Close is called relative to other services. Lower values close earlier; use the CloseEdge/Default/Backend constants. Services that do not implement it close at CloseDefault.
type Config ¶ added in v0.4.0
Config is the full application configuration loaded at startup.
func ReadConfig ¶ added in v0.11.0
ReadConfig reads the standard host configuration sections as a standalone call.
type ErrSource ¶ added in v0.19.0
type ErrSource interface {
ErrCh() <-chan error
}
ErrSource is an optional interface for services that run a background loop and report its fatal outcome on a channel (e.g. the HTTP server's listener). Run merges every started service's channel and treats a delivery like a shutdown trigger, so a crashing long-running service brings the app down cleanly.
type HandlerFunc ¶
HandlerFunc is a setup/lifecycle callback that receives the App and may fail.
type KeyedModule ¶ added in v0.10.0
type KeyedModule interface {
ModuleKey() string
}
KeyedModule is an optional interface for modules that may be installed more than once with different configuration. The returned key identifies the instance for deduplication; two instances with distinct keys both install. Modules that do not implement it are deduplicated by their Go type.
type Module ¶ added in v0.10.0
Module is a composable unit of functionality. Register installs the module's services, routes, workers, config, and any child modules into the App. Modules compose: a module's Register may install further modules via app.WithModule, forming a tree. Composition happens at build time — by the time services are initialized, everything a module declared is in the container.
Convention: Register only *provides* (ProvideService) and *imports* child modules; it must not resolve dependencies, because sibling and child modules may register afterwards. Cross-service wiring belongs in each service's Init(app)/Start(app), which runs in a later phase once every module has registered.
func KeyedModuleFunc ¶ added in v0.19.0
KeyedModuleFunc adapts fn into a Module that deduplicates by key: installing two modules with the same key runs Register only once (first wins), exactly like the struct-module diamond dedup. Satellite Module constructors use it so that installing, say, httpx.Module() twice yields one server instead of silently registering a second that clobbers the first. The key also names the module in logs, so make it readable and unique per slot (e.g. include the instance name).
type ModuleFunc ¶ added in v0.10.0
ModuleFunc adapts a plain function into a Module for small, inline modules that do not need their own type. ModuleFunc values are anonymous and never deduplicated — install them at most once, or use KeyedModuleFunc when the module fills a single slot and double-installation should be a no-op.
func (ModuleFunc) Register ¶ added in v0.10.0
func (f ModuleFunc) Register(app *App) error
Register implements Module.
type NamedModule ¶ added in v0.10.0
type NamedModule interface {
ModuleName() string
}
NamedModule is an optional interface; when a module implements it, the returned name is used in logs and error messages instead of the Go type name.
type Option ¶
type Option func(*App)
Option configures an App at construction time.
func WithClock ¶
func WithClock(clock core.TimeProvider) Option
WithClock injects the time source used by the App and its components. Pass core.UTC in production (the default) or a *core.FixedClock in tests to make time-dependent behavior deterministic.
func WithCloseTimeout ¶ added in v0.19.0
WithCloseTimeout bounds how long Close waits for managed resources (HTTP server, databases, messaging, services) to stop. Defaults to 15s.
func WithConfigReader ¶ added in v0.31.0
WithConfigReader injects the configuration source, bypassing the default TOML file discovery. Use it to embed the App in a host process that already owns configuration, or to supply fixed config in tests (see configx.NewMapReader).
Precedence note: whatever the injected Reader returns is authoritative. The default env-var override shim applies only to the built-in Viper file reader, so an injected reader is not subject to it unless it implements that itself.
func WithConfigValue ¶ added in v0.31.0
WithConfigValue sets a single configuration value in code, keyed by its dotted path (e.g. "app.debug", "app.shutdownDelay", "http.port"). Programmatic values are authoritative: they win over config files, environment variables, and defaults. Apply several at once with WithConfigValues.
It works with the default file reader and with any injected reader that implements configx.Setter (both the file reader and configx.NewMapReader do); New returns an error if the active reader does not support it.
func WithConfigValues ¶ added in v0.31.0
WithConfigValues sets several configuration values in code at once, each keyed by its dotted path. Equivalent to calling WithConfigValue per entry; when keys collide the last write wins. See WithConfigValue for precedence and reader requirements.
func WithEnvPrefix ¶
WithEnvPrefix overrides the environment-variable prefix used for config overrides (defaults to "APP", e.g. APP_HTTP_PORT).
type PeriodicWorker ¶
PeriodicWorker is implemented by DI-registered services that should run on a fixed interval. Run is called immediately on start, then again after each Interval. The next call never starts until the previous one has returned.