Documentation
¶
Overview ¶
Package gaz provides a simple, type-safe dependency injection container with lifecycle management for Go applications.
Quick Start ¶
Create an application, register providers, build, and run:
app := gaz.New()
gaz.For[*Database](app.Container()).Provider(func(c *gaz.Container) (*Database, error) {
return &Database{DSN: "postgres://..."}, nil
})
if err := app.Build(); err != nil {
log.Fatal(err)
}
app.Run(context.Background())
Service Scopes ¶
Services can be registered with different scopes using the For fluent API:
- Singleton: One instance for container lifetime (default). Use For[T].Provider().
- Transient: New instance on every resolution. Use For[T].Transient().Provider().
- Eager: Singleton instantiated at [Container.Build] time. Use For[T].Eager().Provider().
Examples:
gaz.For[*Service](c).Provider(NewService) // Lazy singleton (default) gaz.For[*Service](c).Transient().Provider(NewService) // New instance each time gaz.For[*Pool](c).Eager().Provider(NewPool) // Created at Build() time
Lifecycle Management ¶
Services implementing Starter or Stopper get automatic lifecycle hooks. [Starter.OnStart] is called after App.Build, and [Stopper.OnStop] is called during graceful shutdown.
type Server struct{}
func (s *Server) OnStart(ctx context.Context) error {
return s.listen()
}
func (s *Server) OnStop(ctx context.Context) error {
return s.shutdown()
}
Hooks are called in dependency order: dependencies start first and stop last. Shutdown timeout is configurable via WithShutdownTimeout, with per-hook limits via WithPerHookTimeout.
Configuration ¶
Load configuration from files, environment variables, and CLI flags:
type Config struct {
Port int `mapstructure:"port" validate:"required,min=1"`
Host string `mapstructure:"host" validate:"required"`
}
import "github.com/petabytecl/gaz/config"
app := gaz.New()
app.WithConfig(&Config{}, config.WithEnvPrefix("APP"))
The config struct is automatically registered in the container. Use [ConfigManager] for advanced scenarios. Config values are validated using struct tags with go-playground/validator.
Health Checks ¶
The health subpackage provides HTTP health check endpoints:
import healthmod "github.com/petabytecl/gaz/health/module" app.Use(healthmod.New())
See the health package for health.Manager, readiness, and liveness probes.
Resolution ¶
Resolve dependencies from the container using Resolve:
db, err := gaz.Resolve[*Database](c)
if errors.Is(err, gaz.ErrDINotFound) {
// Handle missing dependency
}
For named registrations, use the Named option:
primary, _ := gaz.Resolve[*sql.DB](c, gaz.Named("primary"))
replica, _ := gaz.Resolve[*sql.DB](c, gaz.Named("replica"))
Modules ¶
Group related providers into reusable modules:
app.Module("database",
func(c *gaz.Container) error {
return gaz.For[*Pool](c).Provider(NewPool)
},
func(c *gaz.Container) error {
return gaz.For[*UserRepo](c).Provider(NewUserRepo)
},
)
See App.Module for details.
Example (Lifecycle) ¶
Example_lifecycle demonstrates registering services with lifecycle hooks. Services implementing Starter and Stopper interfaces have their OnStart/OnStop methods called automatically during App lifecycle.
package main
import (
"context"
"fmt"
"github.com/petabytecl/gaz"
)
// Server demonstrates a service with lifecycle hooks.
type Server struct {
started bool
port int
}
// OnStart is called when the service starts.
func (s *Server) OnStart(_ context.Context) error {
s.started = true
return nil
}
// OnStop is called when the service stops.
func (s *Server) OnStop(_ context.Context) error {
s.started = false
return nil
}
func main() {
app := gaz.New()
// Register Server - it implements Starter and Stopper interfaces
err := gaz.For[*Server](app.Container()).Provider(func(c *gaz.Container) (*Server, error) {
return &Server{port: 8080}, nil
})
if err != nil {
fmt.Println("error:", err)
return
}
if err := app.Build(); err != nil {
fmt.Println("error:", err)
return
}
svc, _ := gaz.Resolve[*Server](app.Container())
fmt.Println("server registered, port:", svc.port)
}
Output: server registered, port: 8080
Example (LifecycleOrder) ¶
Example_lifecycleOrder demonstrates that dependencies start before dependents. When Service A depends on Service B, B's OnStart is called before A's OnStart. During shutdown, the order is reversed: A stops before B.
package main
import (
"context"
"fmt"
"github.com/petabytecl/gaz"
)
// Database demonstrates a dependency that starts first.
type Database struct {
connected bool
}
func (d *Database) OnStart(_ context.Context) error {
d.connected = true
return nil
}
func (d *Database) OnStop(_ context.Context) error {
d.connected = false
return nil
}
// AppServer depends on Database, demonstrating startup order.
type AppServer struct {
db *Database
}
func (s *AppServer) OnStart(_ context.Context) error {
return nil
}
func (s *AppServer) OnStop(_ context.Context) error {
return nil
}
func main() {
c := gaz.NewContainer()
// Register Database (no dependencies)
err := gaz.For[*Database](c).Provider(func(_ *gaz.Container) (*Database, error) {
return &Database{}, nil
})
if err != nil {
fmt.Println("error:", err)
return
}
// Register AppServer (depends on Database)
err = gaz.For[*AppServer](c).Provider(func(c *gaz.Container) (*AppServer, error) {
db, err := gaz.Resolve[*Database](c)
if err != nil {
return nil, err
}
return &AppServer{db: db}, nil
})
if err != nil {
fmt.Println("error:", err)
return
}
// Resolve to establish dependency graph
server, _ := gaz.Resolve[*AppServer](c)
fmt.Println("server has database:", server.db != nil)
}
Output: server has database: true
Index ¶
- Variables
- func ComputeShutdownOrder(startupOrder [][]string) [][]string
- func ComputeStartupOrder(graph map[string][]string, services map[string]di.ServiceWrapper) ([][]string, error)
- func For[T any](c *Container) *di.RegistrationBuilder[T]
- func GetArgs(c *di.Container) []string
- func Has[T any](c *Container) bool
- func MustResolve[T any](c *Container, opts ...di.ResolveOption) T
- func Named(name string) di.ResolveOption
- func Resolve[T any](c *Container, opts ...di.ResolveOption) (T, error)
- func ResolveAll[T any](c *Container) ([]T, error)
- func ResolveGroup[T any](c *Container, group string) ([]T, error)
- func TypeName[T any]() string
- type App
- func (a *App) AddFlagsFn(fn func(*pflag.FlagSet))
- func (a *App) Build() error
- func (a *App) Container() *Container
- func (a *App) EventBus() *eventbus.EventBus
- func (a *App) MergeConfigMap(cfg map[string]any) error
- func (a *App) Module(name string, registrations ...func(*Container) error) *App
- func (a *App) RegisterCobraFlags(cmd *cobra.Command) error
- func (a *App) Run(ctx context.Context) error
- func (a *App) Start(ctx context.Context) error
- func (a *App) Stop(ctx context.Context) error
- func (a *App) Use(m Module) *App
- func (a *App) UseDI(m di.Module) *App
- func (a *App) WithConfig(target any, opts ...config.Option) *App
- type AppOptions
- type CommandArgs
- type ConfigFlag
- type ConfigFlagType
- type ConfigProvider
- type Container
- type CronJob
- type FieldError
- type HookConfig
- type HookFunc
- type HookOption
- type LifecycleError
- type Module
- type ModuleBuilder
- func (b *ModuleBuilder) Build() Module
- func (b *ModuleBuilder) Flags(fn func(*pflag.FlagSet)) *ModuleBuilder
- func (b *ModuleBuilder) Provide(fns ...func(*Container) error) *ModuleBuilder
- func (b *ModuleBuilder) Use(m Module) *ModuleBuilder
- func (b *ModuleBuilder) WithEnvPrefix(prefix string) *ModuleBuilder
- type Option
- type ProviderValues
- func (pv *ProviderValues) GetBool(key string) bool
- func (pv *ProviderValues) GetDuration(key string) time.Duration
- func (pv *ProviderValues) GetFloat64(key string) float64
- func (pv *ProviderValues) GetInt(key string) int
- func (pv *ProviderValues) GetString(key string) string
- func (pv *ProviderValues) Unmarshal(target any) error
- func (pv *ProviderValues) UnmarshalKey(key string, target any) error
- type RegistrationBuilder
- type ResolutionError
- type ResolveOption
- type ServiceWrapper
- type Starter
- type Stopper
- type ValidationError
- type Worker
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrDINotFound is returned when a requested service is not registered in the container. // Check with: errors.Is(err, gaz.ErrDINotFound). ErrDINotFound = di.ErrNotFound // ErrDICycle is returned when a circular dependency is detected during resolution. // Check with: errors.Is(err, gaz.ErrDICycle). ErrDICycle = di.ErrCycle // ErrDIDuplicate is returned when attempting to register a service that already exists. // Check with: errors.Is(err, gaz.ErrDIDuplicate). ErrDIDuplicate = di.ErrDuplicate // ErrDINotSettable is returned when a struct field cannot be set during injection. // Check with: errors.Is(err, gaz.ErrDINotSettable). ErrDINotSettable = di.ErrNotSettable // ErrDITypeMismatch is returned when a resolved service cannot be assigned to the target type. // Check with: errors.Is(err, gaz.ErrDITypeMismatch). ErrDITypeMismatch = di.ErrTypeMismatch // ErrDIAlreadyBuilt is returned when attempting to register after Build() was called. // Check with: errors.Is(err, gaz.ErrDIAlreadyBuilt). ErrDIAlreadyBuilt = di.ErrAlreadyBuilt // ErrDIInvalidProvider is returned when a provider function has invalid signature. // Check with: errors.Is(err, gaz.ErrDIInvalidProvider). ErrDIInvalidProvider = di.ErrInvalidProvider // ErrDIAmbiguous is returned when multiple services are registered for the same key. // Check with: errors.Is(err, gaz.ErrDIAmbiguous). ErrDIAmbiguous = di.ErrAmbiguous )
DI subsystem errors. These are re-exports from the di package with standardized ErrDI* naming. Use errors.Is(err, gaz.ErrDI*) to check for these errors.
Note: Due to Go's import cycle constraints (gaz imports di), the canonical source of DI errors is di/errors.go. These are aliases that point to the same error values, ensuring errors.Is compatibility.
var ( // ErrConfigValidation is returned when config struct validation fails. // Check with: errors.Is(err, gaz.ErrConfigValidation) or errors.Is(err, config.ErrConfigValidation). ErrConfigValidation = config.ErrConfigValidation // ErrConfigNotFound is returned when a config key/namespace doesn't exist. // Check with: errors.Is(err, gaz.ErrConfigNotFound) or errors.Is(err, config.ErrKeyNotFound). ErrConfigNotFound = config.ErrKeyNotFound )
Config subsystem errors. These are re-exports from the config package with standardized ErrConfig* naming. Use errors.Is(err, gaz.ErrConfig*) to check for these errors.
Note: Due to Go's import cycle constraints, the canonical source of config errors is config/errors.go. These are aliases that point to the same error values, ensuring errors.Is compatibility.
var ( // ErrWorkerCircuitTripped indicates a worker exhausted its restart attempts // within the configured circuit window. The worker will not be restarted // until the application is restarted. ErrWorkerCircuitTripped = worker.ErrCircuitBreakerTripped // ErrWorkerStopped indicates a worker stopped normally without error. // This is not an error condition - it signals clean shutdown. ErrWorkerStopped = worker.ErrWorkerStopped // ErrWorkerCriticalFailed indicates a critical worker failed and exhausted // its restart attempts. This error triggers application shutdown. ErrWorkerCriticalFailed = worker.ErrCriticalWorkerFailed // ErrWorkerManagerRunning indicates an attempt to register a worker // after the manager has started. ErrWorkerManagerRunning = worker.ErrManagerAlreadyRunning )
Worker subsystem errors. These are re-exports from the worker package with standardized ErrWorker* naming. Use errors.Is(err, gaz.ErrWorker*) to check for these errors.
Note: Due to Go's import cycle constraints, the canonical source of worker errors is worker/errors.go. These are aliases that point to the same error values, ensuring errors.Is compatibility.
var ( // ErrModuleDuplicate is returned when a module with the same name is registered twice. ErrModuleDuplicate = errors.New("gaz: duplicate module") // ErrConfigKeyCollision is returned when two providers register the same config key. ErrConfigKeyCollision = errors.New("gaz: config key collision") )
Module errors (gaz-specific).
var ( // ErrCronNotRunning indicates an operation was attempted on a scheduler // that is not running. ErrCronNotRunning = cron.ErrNotRunning )
Cron subsystem errors. These are re-exports from the cron package with standardized ErrCron* naming. Use errors.Is(err, gaz.ErrCron*) to check for these errors.
Note: Due to Go's import cycle constraints, the canonical source of cron errors is cron/errors.go. These are aliases that point to the same error values, ensuring errors.Is compatibility.
Functions ¶
func ComputeShutdownOrder ¶
ComputeShutdownOrder reverses the startup order for safe shutdown.
func ComputeStartupOrder ¶
func ComputeStartupOrder( graph map[string][]string, services map[string]di.ServiceWrapper, ) ([][]string, error)
ComputeStartupOrder calculates the order in which services should be started. It returns a list of layers, where each layer contains services that can be started in parallel.
graph: A map where key is the service name and value is the list of dependencies. services: A map of service wrappers to check for lifecycle hooks.
func For ¶
func For[T any](c *Container) *di.RegistrationBuilder[T]
For returns a registration builder for type T.
Example:
gaz.For[*MyService](c).Provider(NewMyService)
Example (Provider) ¶
ExampleFor_provider demonstrates dependency injection with For[T](). The provider function receives the Container for resolving dependencies.
package main
import (
"fmt"
"github.com/petabytecl/gaz"
)
// Logger is a service that other services depend on.
type Logger struct {
Level string
}
// UserService demonstrates dependency injection.
type UserService struct {
logger *Logger
}
func main() {
app := gaz.New()
// Register Logger first
err := gaz.For[*Logger](app.Container()).Provider(func(c *gaz.Container) (*Logger, error) {
return &Logger{Level: "info"}, nil
})
if err != nil {
fmt.Println("error:", err)
return
}
// UserService depends on Logger
err = gaz.For[*UserService](app.Container()).Provider(func(c *gaz.Container) (*UserService, error) {
logger, resolveErr := gaz.Resolve[*Logger](c)
if resolveErr != nil {
return nil, resolveErr
}
return &UserService{logger: logger}, nil
})
if err != nil {
fmt.Println("error:", err)
return
}
if err := app.Build(); err != nil {
fmt.Println("error:", err)
return
}
svc, _ := gaz.Resolve[*UserService](app.Container())
fmt.Println("logger level:", svc.logger.Level)
}
Output: logger level: info
Example (Singleton) ¶
ExampleFor_singleton demonstrates registering a singleton service. Singletons return the same instance on every resolution.
package main
import (
"fmt"
"github.com/petabytecl/gaz"
)
// Counter tracks resolution calls for singleton vs transient demo.
type Counter struct {
value int
}
func (c *Counter) Next() int {
c.value++
return c.value
}
func main() {
c := gaz.NewContainer()
counter := &Counter{}
err := gaz.For[*Counter](c).Instance(counter)
if err != nil {
fmt.Println("error:", err)
return
}
// Resolve twice - same instance returned
c1, _ := gaz.Resolve[*Counter](c)
c2, _ := gaz.Resolve[*Counter](c)
fmt.Println("same instance:", c1 == c2)
}
Output: same instance: true
Example (Transient) ¶
ExampleFor_transient demonstrates registering a transient service. Transient services return a new instance on every resolution.
package main
import (
"fmt"
"github.com/petabytecl/gaz"
)
// Counter tracks resolution calls for singleton vs transient demo.
type Counter struct {
value int
}
func (c *Counter) Next() int {
c.value++
return c.value
}
func main() {
c := gaz.NewContainer()
callCount := 0
err := gaz.For[*Counter](c).Transient().Provider(func(_ *gaz.Container) (*Counter, error) {
callCount++
return &Counter{value: callCount * 100}, nil
})
if err != nil {
fmt.Println("error:", err)
return
}
// Resolve twice - different instances created
c1, _ := gaz.Resolve[*Counter](c)
c2, _ := gaz.Resolve[*Counter](c)
fmt.Println("different instances:", c1 != c2)
fmt.Println("c1 value:", c1.value)
fmt.Println("c2 value:", c2.value)
}
Output: different instances: true c1 value: 100 c2 value: 200
func GetArgs ¶
GetArgs retrieves the CLI arguments from the DI container. It returns nil if CommandArgs is not available in the container.
func MustResolve ¶
func MustResolve[T any](c *Container, opts ...di.ResolveOption) T
MustResolve resolves a service or panics if resolution fails.
func Named ¶
func Named(name string) di.ResolveOption
Named resolves a service by its registered name instead of type.
func Resolve ¶
func Resolve[T any](c *Container, opts ...di.ResolveOption) (T, error)
Resolve retrieves a service of type T from the container.
Example ¶
ExampleResolve demonstrates resolving a registered service.
package main
import (
"fmt"
"github.com/petabytecl/gaz"
)
// Logger is a service that other services depend on.
type Logger struct {
Level string
}
func main() {
c := gaz.NewContainer()
// Register a configuration instance
err := gaz.For[*Logger](c).Instance(&Logger{Level: "debug"})
if err != nil {
fmt.Println("error:", err)
return
}
// Resolve the service
logger, err := gaz.Resolve[*Logger](c)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("level:", logger.Level)
}
Output: level: debug
func ResolveAll ¶
ResolveAll retrieves all registered services of type T.
func ResolveGroup ¶
ResolveGroup retrieves all services belonging to the specified group. It filters services that are assignable to T.
Types ¶
type App ¶
type App struct {
// Logger instance - nil until Build() is called
Logger *slog.Logger
// contains filtered or unexported fields
}
App is the application runtime wrapper. It orchestrates dependency injection, lifecycle management, and signal handling.
func FromContext ¶
FromContext retrieves the App from a context. Returns nil if no App is found. Use this in Cobra command handlers to access the DI container.
Example:
var serveCmd = &cobra.Command{
Use: "serve",
RunE: func(cmd *cobra.Command, args []string) error {
app := gaz.FromContext(cmd.Context())
server, err := gaz.Resolve[*HTTPServer](app.Container())
if err != nil {
return err
}
return server.ListenAndServe()
},
}
func New ¶
New creates a new App with the given options. Use the For[T]() fluent API to register services, then call Build() and Run().
Logger, WorkerManager, Scheduler, and EventBus are NOT created here. They are initialized in Build() after config is loaded and flags are parsed. This allows logger CLI flags to take effect.
Example:
app := gaz.New(gaz.WithShutdownTimeout(10 * time.Second))
gaz.For[*Database](app.Container()).Provider(NewDatabase)
gaz.For[*Request](app.Container()).Transient().Provider(NewRequest)
if err := app.Build(); err != nil {
log.Fatal(err)
}
app.Run(ctx)
Example ¶
ExampleNew demonstrates basic app creation and provider registration.
package main
import (
"fmt"
"github.com/petabytecl/gaz"
)
// MyService is a simple service for demonstration.
type MyService struct {
Name string
}
func main() {
app := gaz.New()
err := gaz.For[*MyService](app.Container()).Provider(func(c *gaz.Container) (*MyService, error) {
return &MyService{Name: "example"}, nil
})
if err != nil {
fmt.Println("error:", err)
return
}
if err := app.Build(); err != nil {
fmt.Println("error:", err)
return
}
svc, err := gaz.Resolve[*MyService](app.Container())
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(svc.Name)
}
Output: example
func (*App) AddFlagsFn ¶
AddFlagsFn registers a function that adds flags to the application. Flags are stored and applied when WithCobra option is processed or when a Cobra command is attached. If a Cobra command is already attached, flags are applied immediately.
func (*App) Build ¶
Build validates all registrations and instantiates eager services. It aggregates all errors and returns them using errors.Join. Build is idempotent - calling it multiple times after success returns nil.
func (*App) Container ¶
Container returns the underlying container. This is useful for advanced use cases or testing.
func (*App) EventBus ¶
EventBus returns the application's EventBus for pub/sub. Returns nil if called before Build(). Prefer injecting *eventbus.EventBus as a dependency instead.
func (*App) MergeConfigMap ¶
MergeConfigMap merges raw config values into the app's configuration. This is primarily intended for testing scenarios where you want to inject config values without loading from files.
Must be called before Build(). Panics if called after Build().
func (*App) Module ¶
Module registers a named group of providers. The name is used for debugging and error messages. Duplicate module names result in ErrModuleDuplicate error during Build().
Each registration should be a function that accepts *Container and returns error. This allows using the For[T]() fluent API within modules.
Example:
app.Module("database",
func(c *gaz.Container) error { return gaz.For[*DB](c).Provider(NewDB) },
func(c *gaz.Container) error { return gaz.For[*UserRepo](c).Provider(NewUserRepo) },
).Module("http",
func(c *gaz.Container) error { return gaz.For[*Server](c).Provider(NewServer) },
)
func (*App) RegisterCobraFlags ¶
RegisterCobraFlags registers ConfigProvider flags as persistent pflags on the command. This must be called BEFORE cmd.Execute() for flags to appear in --help output.
The method: 1. Loads configuration (so defaults are available) 2. Registers ProviderValues for provider dependency injection 3. Collects ConfigProvider flags from registered services 4. Registers typed pflags on cmd.PersistentFlags() 5. Binds each flag to viper with the original dot-notation key
Example:
app := gaz.New() gaz.For[*ServerConfig](app.Container()).Provider(NewServerConfig) app.RegisterCobraFlags(rootCmd) // Register before Execute app.WithCobra(rootCmd) rootCmd.Execute()
func (*App) Run ¶
Run executes the application lifecycle. It builds the container, starts services in order, and waits for a signal or stop call.
func (*App) Start ¶
Start initiates the application lifecycle. This is called automatically by WithCobra() or can be called manually. It executes OnStart hooks for all services in dependency order.
func (*App) Stop ¶
Stop initiates graceful shutdown of the application. It executes OnStop hooks for all services in reverse dependency order. Safe to call even if Run() was not used (e.g., Cobra integration). Stop is idempotent - calling it multiple times returns the same result.
func (*App) Use ¶
Use applies a module to the app's container. Modules bundle providers, configs, and other modules for reuse.
Use accepts both gaz.Module (built via gaz.NewModule().Build()) and di.Module (returned by subsystem packages like worker.NewModule()). This allows subsystem packages to export modules without importing gaz, avoiding import cycles.
Child modules bundled via ModuleBuilder.Use() are applied BEFORE the parent module's providers. This is for composition convenience, not dependency ordering (which is handled by the DI container).
If the module provides CLI flags (via ModuleBuilder.Flags()) and the app has a Cobra command attached (via WithCobra), the flags are registered on the command's PersistentFlags.
Returns error on duplicate module name (collected during Build()). Panics if called after Build().
Example:
module := gaz.NewModule("database").
Provide(func(c *gaz.Container) error {
return gaz.For[*DB](c).Provider(NewDB)
}).
Build()
app := gaz.New().
Use(module).
Use(worker.NewModule()). // di.Module from subsystem
Use(cacheModule).
Build()
func (*App) UseDI ¶
UseDI applies a di.Module to the app's container. This is for subsystem packages (health, worker, cron, eventbus) that return di.Module to avoid import cycles with the gaz package.
The di.Module interface has Register(c *Container) instead of Apply(app *App), which allows subsystem packages to export modules without importing gaz.
Example:
app := gaz.New().
UseDI(worker.NewModule()).
Build()
func (*App) WithConfig ¶
WithConfig configures the application to load configuration into the target struct. The target must be a pointer to a struct, or nil to only customize config options.
The configuration is loaded from: 1. Defaults (via Defaulter interface) 2. Config files (yaml, json, toml) in specified paths 3. Environment variables (if WithEnvPrefix is set) 4. Flags (if WithCobra is used)
By default, gaz looks for config.yaml in the current directory. Use this method to: - Load config into a struct (target != nil) - Customize config options (change search paths, env prefix, etc.)
If you only use ConfigProvider pattern for config, you don't need to call this method.
type AppOptions ¶
type AppOptions struct {
ShutdownTimeout time.Duration
PerHookTimeout time.Duration
LoggerConfig *logger.Config
}
AppOptions configuration for App.
type CommandArgs ¶
CommandArgs holds the Cobra command and arguments for the current execution. It is available in the DI container for services that need access to CLI inputs.
type ConfigFlag ¶
type ConfigFlag struct {
// Key is the config key relative to the provider's namespace.
// For example, if a provider declares namespace "redis" and key "host",
// the full config key becomes "redis.host".
Key string
// Type specifies how the config value should be parsed.
// String values are used as-is, while int, bool, duration, and float
// values are parsed from their string representation.
Type ConfigFlagType
// Default is the default value to use if the config key is not set.
// Set to nil for no default. The type should match the Type field
// (e.g., int for ConfigFlagTypeInt, time.Duration for ConfigFlagTypeDuration).
Default any
// Required indicates whether this config key must be set.
// If true and the key is not set (via env, file, or flag),
// the application will fail to start during Build().
Required bool
// Description provides help text for this config key.
// Used in --help output and documentation generation.
Description string
}
ConfigFlag defines a configuration key that a provider needs. Providers return a slice of ConfigFlag from their ConfigFlags() method to declare their configuration requirements.
Example:
func (r *RedisProvider) ConfigFlags() []gaz.ConfigFlag {
return []gaz.ConfigFlag{
{Key: "host", Type: gaz.ConfigFlagTypeString, Default: "localhost", Description: "Redis server host"},
{Key: "port", Type: gaz.ConfigFlagTypeInt, Default: 6379, Description: "Redis server port"},
{Key: "password", Type: gaz.ConfigFlagTypeString, Required: true, Description: "Redis password"},
}
}
type ConfigFlagType ¶
type ConfigFlagType string
ConfigFlagType represents the type of a configuration flag value. The framework uses this to parse and validate config values correctly.
const ( // ConfigFlagTypeString represents a string configuration value. ConfigFlagTypeString ConfigFlagType = "string" // ConfigFlagTypeInt represents an integer configuration value. ConfigFlagTypeInt ConfigFlagType = "int" // ConfigFlagTypeBool represents a boolean configuration value. ConfigFlagTypeBool ConfigFlagType = "bool" // ConfigFlagTypeDuration represents a time.Duration configuration value. // Values are parsed using time.ParseDuration (e.g., "30s", "5m", "1h"). ConfigFlagTypeDuration ConfigFlagType = "duration" // ConfigFlagTypeFloat represents a float64 configuration value. ConfigFlagTypeFloat ConfigFlagType = "float" )
type ConfigProvider ¶
type ConfigProvider interface {
// ConfigNamespace returns the namespace prefix for this provider's config keys.
// All keys returned by ConfigFlags() are automatically prefixed with this namespace.
// For example, if namespace is "redis" and a key is "host", the full key is "redis.host".
ConfigNamespace() string
// ConfigFlags returns the configuration flags this provider needs.
// Each flag describes a config key with its type, default value, and whether it's required.
ConfigFlags() []ConfigFlag
}
ConfigProvider is implemented by providers that need configuration. When a provider implements this interface, the framework will:
- Call ConfigNamespace() to get the prefix for all config keys
- Call ConfigFlags() to collect configuration requirements
- Auto-prefix each key with the namespace (e.g., "redis" + "host" = "redis.host")
- Translate keys for environment variables (e.g., "redis.host" → "REDIS_HOST")
- Validate required flags are set during Build()
Providers define their config needs but do not receive values directly. Config values are accessible via ProviderValues, which is injectable.
Example:
type RedisProvider struct{}
func (r *RedisProvider) ConfigNamespace() string {
return "redis"
}
func (r *RedisProvider) ConfigFlags() []gaz.ConfigFlag {
return []gaz.ConfigFlag{
{Key: "host", Type: gaz.ConfigFlagTypeString, Default: "localhost", Description: "Redis server host"},
{Key: "port", Type: gaz.ConfigFlagTypeInt, Default: 6379, Description: "Redis server port"},
}
}
type Container ¶
Container is a type alias for di.Container. This allows provider functions to use *gaz.Container in their signatures.
func NewContainer ¶
func NewContainer() *Container
NewContainer creates a new empty Container. For standalone DI usage, you may also use di.New() directly.
type CronJob ¶
CronJob is a type alias for cron.CronJob for convenience. Users can import this from the root gaz package instead of gaz/cron.
type FieldError ¶
type FieldError = config.FieldError
FieldError represents a single field validation failure. This is a type alias for config.FieldError.
func NewFieldError ¶
func NewFieldError(namespace, tag, param, message string) FieldError
NewFieldError creates a new FieldError with the given parameters. This is a convenience wrapper for config.NewFieldError.
type HookConfig ¶
type HookConfig = di.HookConfig
HookConfig holds configuration for lifecycle hooks.
type HookOption ¶
type HookOption = di.HookOption
HookOption configures a lifecycle hook.
func WithHookTimeout ¶
func WithHookTimeout(d time.Duration) HookOption
WithHookTimeout sets a custom timeout for this specific hook. If not set, the hook uses the App's default PerHookTimeout.
type LifecycleError ¶
type LifecycleError struct {
// ServiceName is the service that failed during lifecycle.
ServiceName string
// Phase is the lifecycle phase that failed: "start" or "stop".
Phase string
// Cause is the underlying error.
Cause error
}
LifecycleError represents a failure during service start or stop. Use errors.As to extract which service failed and in which phase.
func (*LifecycleError) Error ¶
func (e *LifecycleError) Error() string
Error implements the error interface.
func (*LifecycleError) Unwrap ¶
func (e *LifecycleError) Unwrap() error
Unwrap returns the underlying cause.
type Module ¶
type Module interface {
// Name returns the module's identifier for debugging and error messages.
Name() string
// Apply applies the module's providers to the app.
// Child modules are applied before the parent module's providers.
Apply(app *App) error
}
Module represents a reusable bundle of providers. Modules can be composed using the Use() method to bundle child modules. When a module is applied, its child modules are applied first.
type ModuleBuilder ¶
type ModuleBuilder struct {
// contains filtered or unexported fields
}
ModuleBuilder constructs Module instances via fluent API. Use NewModule(name) to start building a module.
Example:
module := gaz.NewModule("database").
Provide(func(c *gaz.Container) error {
return gaz.For[*DB](c).Provider(NewDB)
}).
Build()
app.Use(module)
func NewModule ¶
func NewModule(name string) *ModuleBuilder
NewModule creates a new ModuleBuilder with the given name. The name is used for debugging, error messages, and duplicate detection.
Example:
module := gaz.NewModule("redis").
Provide(RedisProvider).
Build()
func (*ModuleBuilder) Build ¶
func (b *ModuleBuilder) Build() Module
Build creates the final Module. After Build() is called, the ModuleBuilder should not be reused.
func (*ModuleBuilder) Flags ¶
func (b *ModuleBuilder) Flags(fn func(*pflag.FlagSet)) *ModuleBuilder
Flags registers CLI flags for this module. The flags function receives a FlagSet to register module-specific flags. Flags should be namespaced by module name (e.g., "redis-host" not "host") to avoid collisions with other modules.
The flags function is called when the module is applied to an App that has a Cobra command attached (via WithCobra). If no Cobra command is attached, the flags function is not called.
Example:
module := gaz.NewModule("redis").
Flags(func(fs *pflag.FlagSet) {
fs.String("redis-host", "localhost", "Redis server host")
fs.Int("redis-port", 6379, "Redis server port")
}).
Build()
func (*ModuleBuilder) Provide ¶
func (b *ModuleBuilder) Provide(fns ...func(*Container) error) *ModuleBuilder
Provide adds provider functions to the module. Each function receives *Container and returns error. This method is chainable.
Example:
module := gaz.NewModule("http").
Provide(
func(c *gaz.Container) error { return gaz.For[*Router](c).Provider(NewRouter) },
func(c *gaz.Container) error { return gaz.For[*Server](c).Provider(NewServer) },
).
Build()
func (*ModuleBuilder) Use ¶
func (b *ModuleBuilder) Use(m Module) *ModuleBuilder
Use bundles another module to be applied when this module is applied. Child modules are applied BEFORE this module's providers. This is for composition/bundling convenience, not dependency ordering (dependency ordering is handled by the DI container).
Example:
logging := gaz.NewModule("logging").Provide(LoggerProvider).Build()
metrics := gaz.NewModule("metrics").Provide(MetricsProvider).Build()
observability := gaz.NewModule("observability").
Use(logging).
Use(metrics).
Build()
func (*ModuleBuilder) WithEnvPrefix ¶
func (b *ModuleBuilder) WithEnvPrefix(prefix string) *ModuleBuilder
WithEnvPrefix sets the config key prefix for this module. When combined with service-level env prefix, the module prefix becomes a sub-prefix. For example:
Service prefix: "MYAPP_" Module prefix: "redis" Config key: "host" Result: "MYAPP_REDIS_HOST"
Example:
module := gaz.NewModule("redis").
WithEnvPrefix("redis").
Build()
type Option ¶
type Option func(*App)
Option configures App settings.
func WithCobra ¶
WithCobra attaches the App lifecycle to a Cobra command. This is an Option passed to gaz.New() that hooks into: - PersistentPreRunE: applies stored flags, Build() and Start() the app - PersistentPostRunE: Stop() the app
The App is stored in the command's context, accessible via FromContext().
Existing hooks on the command are preserved and chained (not replaced).
Example:
rootCmd := &cobra.Command{Use: "myapp"}
app := gaz.New(gaz.WithCobra(rootCmd))
gaz.For[*Database](app.Container()).Provider(NewDatabase)
// In subcommand:
app := gaz.FromContext(cmd.Context())
db, _ := gaz.Resolve[*Database](app.Container())
func WithLoggerConfig ¶
WithLoggerConfig sets the logger configuration.
func WithPerHookTimeout ¶
WithPerHookTimeout sets the default timeout for each shutdown hook. Default is 10 seconds. Individual hooks can override via WithHookTimeout.
func WithShutdownTimeout ¶
WithShutdownTimeout sets the timeout for graceful shutdown. Default is 30 seconds.
func WithStrictConfig ¶
func WithStrictConfig() Option
WithStrictConfig enables strict configuration validation. If enabled, Build() fails if the config file contains any keys that are not mapped to fields in the config struct. This helps catch typos and obsolete configuration.
Strict validation is only applied when a config target is set via WithConfig(). It has no effect on ConfigProvider pattern.
type ProviderValues ¶
type ProviderValues struct {
// contains filtered or unexported fields
}
ProviderValues provides access to provider-registered configuration values. Inject this via the DI container to retrieve config values by their full key.
Example:
func NewRedisClient(c *gaz.Container) (*RedisClient, error) {
pv := gaz.MustResolve[*gaz.ProviderValues](c)
host := pv.GetString("redis.host")
port := pv.GetInt("redis.port")
return &RedisClient{Host: host, Port: port}, nil
}
func (*ProviderValues) GetBool ¶
func (pv *ProviderValues) GetBool(key string) bool
GetBool returns a bool config value by its full key.
func (*ProviderValues) GetDuration ¶
func (pv *ProviderValues) GetDuration(key string) time.Duration
GetDuration returns a duration config value by its full key.
func (*ProviderValues) GetFloat64 ¶
func (pv *ProviderValues) GetFloat64(key string) float64
GetFloat64 returns a float64 config value by its full key.
func (*ProviderValues) GetInt ¶
func (pv *ProviderValues) GetInt(key string) int
GetInt returns an int config value by its full key.
func (*ProviderValues) GetString ¶
func (pv *ProviderValues) GetString(key string) string
GetString returns a string config value by its full key (e.g., "redis.host").
func (*ProviderValues) Unmarshal ¶
func (pv *ProviderValues) Unmarshal(target any) error
Unmarshal unmarshals the entire config into target struct. Uses "gaz" struct tags for field mapping.
Example:
type AppConfig struct {
Redis RedisConfig `gaz:"redis"`
DB DBConfig `gaz:"database"`
}
var cfg AppConfig
if err := pv.Unmarshal(&cfg); err != nil {
return err
}
func (*ProviderValues) UnmarshalKey ¶
func (pv *ProviderValues) UnmarshalKey(key string, target any) error
UnmarshalKey unmarshals config at the given key/namespace into target struct. Uses "gaz" struct tags for field mapping. Returns config.ErrKeyNotFound if the key/namespace doesn't exist.
Example:
type RedisConfig struct {
Host string `gaz:"host"`
Port int `gaz:"port"`
}
var cfg RedisConfig
if err := pv.UnmarshalKey("redis", &cfg); err != nil {
if errors.Is(err, config.ErrKeyNotFound) {
// Handle missing namespace
}
return err
}
type RegistrationBuilder ¶
type RegistrationBuilder[T any] = di.RegistrationBuilder[T]
RegistrationBuilder provides a fluent API for configuring services.
type ResolutionError ¶
type ResolutionError struct {
// ServiceName is the service that failed to resolve.
ServiceName string
// Chain is the resolution chain leading to the failure.
// For example: ["App", "UserService", "Database"] shows that
// App depends on UserService which depends on Database which failed.
Chain []string
// Cause is the underlying error that caused the resolution to fail.
Cause error
}
ResolutionError represents a DI resolution failure with context about which service failed and the resolution chain leading to the failure. Use errors.As to extract resolution context for debugging.
func (*ResolutionError) Error ¶
func (e *ResolutionError) Error() string
Error implements the error interface.
func (*ResolutionError) Unwrap ¶
func (e *ResolutionError) Unwrap() error
Unwrap returns the underlying cause, enabling errors.Is and errors.As to work through the error chain.
type ResolveOption ¶
type ResolveOption = di.ResolveOption
ResolveOption modifies resolution behavior.
type ServiceWrapper ¶
type ServiceWrapper = di.ServiceWrapper
ServiceWrapper is the interface for service lifecycle management.
type Starter ¶
Starter is an interface for services that need to perform action on startup. Implementing this interface is the sole mechanism for lifecycle participation. OnStart is called automatically after container Build() when the service is first instantiated. Hooks are called in dependency order: dependencies start first.
This interface is auto-detected by the DI container. No registration of lifecycle hooks is needed - simply implement the interface.
type Stopper ¶
Stopper is an interface for services that need to perform action on shutdown. Implementing this interface is the sole mechanism for lifecycle participation. OnStop is called automatically during graceful shutdown. Hooks are called in reverse dependency order: dependents stop first, then their dependencies.
This interface is auto-detected by the DI container. No registration of lifecycle hooks is needed - simply implement the interface.
type ValidationError ¶
type ValidationError = config.ValidationError
ValidationError holds multiple validation errors from config struct validation. It implements the error interface and provides access to individual field errors. Use errors.Is(err, ErrConfigValidation) to check for validation errors.
This is a type alias for config.ValidationError, ensuring compatibility between gaz and config packages.
func NewValidationError ¶
func NewValidationError(errs []FieldError) ValidationError
NewValidationError creates a ValidationError from a slice of FieldErrors. This is a convenience wrapper for config.NewValidationError.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package backoff provides exponential backoff algorithms for retry logic.
|
Package backoff provides exponential backoff algorithms for retry logic. |
|
Package config provides standalone configuration management for Go applications.
|
Package config provides standalone configuration management for Go applications. |
|
module
Package module provides a gaz.Module for configuring config loading via CLI flags.
|
Package module provides a gaz.Module for configuring config loading via CLI flags. |
|
viper
Package viper provides a viper-based Backend implementation for the config package.
|
Package viper provides a viper-based Backend implementation for the config package. |
|
Package cron provides scheduled task support for Go applications using cron/internal.
|
Package cron provides scheduled task support for Go applications using cron/internal. |
|
internal
Package internal provides internal cron expression parsing and schedule calculation.
|
Package internal provides internal cron expression parsing and schedule calculation. |
|
module
Package module provides the gaz.Module for cron integration.
|
Package module provides the gaz.Module for cron integration. |
|
Package di provides a lightweight, type-safe dependency injection container.
|
Package di provides a lightweight, type-safe dependency injection container. |
|
Package eventbus provides type-safe in-process pub/sub for Go applications.
|
Package eventbus provides type-safe in-process pub/sub for Go applications. |
|
module
Package module provides the gaz.Module for eventbus integration.
|
Package module provides the gaz.Module for eventbus integration. |
|
examples
|
|
|
background-workers
command
Package main demonstrates background worker patterns with gaz.
|
Package main demonstrates background worker patterns with gaz. |
|
basic
command
Package main demonstrates the minimal usage of the gaz DI framework.
|
Package main demonstrates the minimal usage of the gaz DI framework. |
|
cobra-cli
command
Package main demonstrates Cobra CLI integration with gaz.
|
Package main demonstrates Cobra CLI integration with gaz. |
|
config-loading
command
Package main demonstrates the ConfigProvider pattern for flag-based configuration.
|
Package main demonstrates the ConfigProvider pattern for flag-based configuration. |
|
discovery
command
Package main demonstrates the discovery pattern using ResolveAll.
|
Package main demonstrates the discovery pattern using ResolveAll. |
|
http-server
command
Package main demonstrates an HTTP server with graceful shutdown and health checks.
|
Package main demonstrates an HTTP server with graceful shutdown and health checks. |
|
lifecycle
command
Package main demonstrates gaz lifecycle hooks (OnStart/OnStop).
|
Package main demonstrates gaz lifecycle hooks (OnStart/OnStop). |
|
microservice
command
Package main demonstrates a complete microservice with gaz.
|
Package main demonstrates a complete microservice with gaz. |
|
modules
command
Package main demonstrates organizing providers into modules.
|
Package main demonstrates organizing providers into modules. |
|
vanguard
command
Package main demonstrates the Vanguard unified server with gaz.
|
Package main demonstrates the Vanguard unified server with gaz. |
|
Package gaztest provides test utilities for gaz applications.
|
Package gaztest provides test utilities for gaz applications. |
|
Package health provides health check management for gaz applications.
|
Package health provides health check management for gaz applications. |
|
checks
Package checks provides reusable health check implementations for common infrastructure dependencies.
|
Package checks provides reusable health check implementations for common infrastructure dependencies. |
|
checks/disk
Package disk provides a health check for disk space using gopsutil.
|
Package disk provides a health check for disk space using gopsutil. |
|
checks/dns
Package dns provides a health check for DNS hostname resolution.
|
Package dns provides a health check for DNS hostname resolution. |
|
checks/http
Package httpcheck provides a health check for HTTP upstream services.
|
Package httpcheck provides a health check for HTTP upstream services. |
|
checks/pgx
Package pgx provides a health check for PostgreSQL databases using pgx/v5.
|
Package pgx provides a health check for PostgreSQL databases using pgx/v5. |
|
checks/redis
Package redis provides a health check for Redis/Valkey using valkey-go.
|
Package redis provides a health check for Redis/Valkey using valkey-go. |
|
checks/runtime
Package runtime provides health checks based on Go runtime metrics.
|
Package runtime provides health checks based on Go runtime metrics. |
|
checks/sql
Package sql provides a health check for SQL databases using database/sql.
|
Package sql provides a health check for SQL databases using database/sql. |
|
checks/tcp
Package tcp provides a health check for TCP port connectivity.
|
Package tcp provides a health check for TCP port connectivity. |
|
internal
Package internal provides internal health check execution with parallel processing.
|
Package internal provides internal health check execution with parallel processing. |
|
module
Package module provides the gaz.Module for health configuration with CLI flags.
|
Package module provides the gaz.Module for health configuration with CLI flags. |
|
Package logger provides structured logging with context support.
|
Package logger provides structured logging with context support. |
|
module
Package module provides a gaz.Module for configuring the logger via CLI flags.
|
Package module provides a gaz.Module for configuring the logger via CLI flags. |
|
tint
Package tint provides a colored console handler for slog.
|
Package tint provides a colored console handler for slog. |
|
Package server provides a unified transport layer for gaz applications, combining gRPC and Vanguard on a single port with lifecycle management.
|
Package server provides a unified transport layer for gaz applications, combining gRPC and Vanguard on a single port with lifecycle management. |
|
connect
Package connect provides the Registrar interface for auto-discovery of Connect-Go services and the InterceptorBundle interface for auto-discovered interceptor chains within the gaz framework.
|
Package connect provides the Registrar interface for auto-discovery of Connect-Go services and the InterceptorBundle interface for auto-discovered interceptor chains within the gaz framework. |
|
grpc
Package grpc provides a production-ready gRPC server with auto-discovery, interceptors, and lifecycle integration for the gaz framework.
|
Package grpc provides a production-ready gRPC server with auto-discovery, interceptors, and lifecycle integration for the gaz framework. |
|
http
Package http provides a production-ready HTTP server with DI integration.
|
Package http provides a production-ready HTTP server with DI integration. |
|
otel
Package otel provides OpenTelemetry integration for the gaz framework.
|
Package otel provides OpenTelemetry integration for the gaz framework. |
|
vanguard
Package vanguard provides a unified server that serves gRPC, Connect, gRPC-Web, and REST protocols on a single port via Vanguard transcoder with h2c support.
|
Package vanguard provides a unified server that serves gRPC, Connect, gRPC-Web, and REST protocols on a single port via Vanguard transcoder with h2c support. |
|
Package worker provides background worker lifecycle management for Go applications.
|
Package worker provides background worker lifecycle management for Go applications. |
|
module
Package module provides the gaz.Module for worker integration.
|
Package module provides the gaz.Module for worker integration. |