Documentation
¶
Overview ¶
Package types provides the core interfaces for the component-based application framework. It defines the contracts that components must adhere to for lifecycle management, configuration, and monitoring.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Component ¶
type Component interface {
// Type returns a unique identifier for the component type.
// This is used for logging, debugging, and component identification.
// Examples: "database", "http-server", "cache", "logger".
Type() string
// Init is called by the config manager when the component is registered.
// This provides the component with access to shared resources.
//
// Parameters:
// - key: The unique key this component is registered under.
// - ctx: A function to get the shared application context.
// - get: A function to retrieve other components by key (for dependency injection).
// - vpr: A function to get the Viper configuration instance.
// - vrs: Application version information.
// - log: A function to get the default logger instance.
//
// The component should store these for later use during its lifecycle (Start/Reload/Stop).
Init(key string, ctx context.Context, get FuncCptGet, vpr libvpr.FuncViper, vrs libver.Version, log liblog.FuncLog)
// DefaultConfig returns the default JSON configuration for this component.
// This is used by the config manager to generate a complete default config file.
//
// Parameters:
// - indent: The indentation string to use for JSON formatting (e.g., " ").
//
// Returns:
// - A JSON byte slice representing the default configuration.
//
// Example return value:
// {
// "enabled": true,
// "host": "localhost",
// "port": 5432
// }
DefaultConfig(indent string) []byte
// Dependencies returns the list of component keys that this component depends on.
// The config manager uses this for topological sorting to ensure components start
// in the correct order.
//
// Returns:
// - A slice of component keys (empty if no dependencies).
//
// Example:
// return []string{"database", "cache"} // Depends on "database" and "cache" components.
//
// Dependencies are started before this component and stopped after this component.
Dependencies() []string
// SetDependencies allows customizing the component's dependencies at runtime.
// This replaces the default dependencies returned by the Dependencies() method.
//
// Parameters:
// - d: A new list of dependency keys.
//
// Returns:
// - An error if the dependencies are invalid or create circular dependencies.
//
// Use with caution: Ensure that default dependencies are included if they are still needed.
SetDependencies(d []string) error
ComponentViper
ComponentEvent
ComponentMonitor
}
Component is the main interface that all components must implement. It combines lifecycle management (ComponentEvent), configuration (ComponentViper), and monitoring (ComponentMonitor) capabilities.
A component represents a distinct subsystem of the application, such as:
- Database connections
- HTTP servers
- Cache systems
- Message queues
- Background workers
Components are registered with the config manager and managed through their lifecycle.
type ComponentEvent ¶
type ComponentEvent interface {
// RegisterFuncStart registers hooks to be called before and after the Start method.
// The 'before' hook executes before the component's Start() method is called.
// The 'after' hook executes after the component has started successfully.
// This is useful for tasks like initialization logging, dependency verification,
// or post-start validation.
RegisterFuncStart(before, after FuncCptEvent)
// RegisterFuncReload registers hooks to be called before and after the Reload method.
// The 'before' hook executes before the component's Reload() method is called.
// The 'after' hook executes after the component has reloaded successfully.
// This is useful for tasks like configuration backup, reload logging, or
// post-reload validation.
RegisterFuncReload(before, after FuncCptEvent)
// IsStarted returns true if the component has been started.
// This indicates that the Start() method has been called and completed successfully.
// The component may or may not still be actively running.
// This is used by the config manager to verify the component's initialization state.
IsStarted() bool
// IsRunning returns true if the component is actively running.
// This differs from IsStarted() in that it indicates the current runtime state.
// A component can be started but not currently running (e.g., stopped or crashed).
// This is used by the config manager to check the component's health and readiness.
IsRunning() bool
// Start initializes and starts the component.
// This method is called by the config manager in dependency order.
// The component should perform tasks such as:
// - Loading its configuration.
// - Initializing resources (e.g., database connections, client pools).
// - Starting any background goroutines.
// - Setting its started and running state.
// It returns an error if startup fails, which will cause the config manager
// to abort the application's start sequence.
Start() error
// Reload refreshes the component's configuration and restarts it if necessary.
// This method is called by the config manager in dependency order.
// The component should:
// - Reload its configuration from Viper.
// - Apply changes without a full restart if possible.
// - Restart internal services if the configuration has changed significantly.
// It returns an error if the reload fails, which will cause the config manager
// to abort the reload sequence.
Reload() error
// Stop gracefully shuts down the component.
// This method is called by the config manager in reverse dependency order.
// The component must:
// - Stop all background goroutines.
// - Close connections and release all resources.
// - Set its running and started state to false.
// - Complete the shutdown process within a reasonable time.
// This method should not return an error; it must perform cleanup on a best-effort basis.
Stop()
}
ComponentEvent defines the lifecycle interface for components. All components must implement these methods to participate in the application lifecycle managed by the main config.
type ComponentList ¶
type ComponentList interface {
// ComponentHas checks if a component with the given key is registered.
//
// Parameters:
// - key: The component key to check
//
// Returns:
// - bool: true if the component exists, false otherwise
//
// Thread-safe: Can be called concurrently.
ComponentHas(key string) bool
// ComponentType returns the type identifier of the registered component.
//
// Parameters:
// - key: The component key to query
//
// Returns:
// - string: The component type (from Component.Type()), or empty string if not found
//
// Thread-safe: Can be called concurrently.
ComponentType(key string) string
// ComponentGet retrieves a registered component by its key.
//
// Parameters:
// - key: The component key to retrieve
//
// Returns:
// - Component: The component instance, or nil if not found
//
// The returned component can be type-asserted to specific component interfaces:
//
// if db, ok := cfg.ComponentGet("database").(DatabaseComponent); ok {
// db.GetConnection()
// }
//
// Thread-safe: Can be called concurrently.
ComponentGet(key string) Component
// ComponentDel removes a component from the registry.
//
// Parameters:
// - key: The component key to remove
//
// Note: Does not call Stop() on the component. Stop the component first
// if it's running. Other components depending on this component may fail
// if it's removed while they're running.
//
// Thread-safe: Can be called concurrently.
ComponentDel(key string)
// ComponentSet registers a component with the given key.
//
// Parameters:
// - key: Unique identifier for the component
// - cpt: The component instance to register
//
// This method:
// - Calls component.Init() with dependency injection parameters
// - Registers the monitor pool if available
// - Stores the component in the registry
// - Replaces any existing component with the same key
//
// Example:
//
// db := &DatabaseComponent{}
// cfg.ComponentSet("database", db)
//
// Thread-safe: Can be called concurrently.
ComponentSet(key string, cpt Component)
// ComponentList returns all registered components as a map.
//
// Returns:
// - map[string]Component: Map of component keys to component instances
//
// The returned map is a snapshot; modifications don't affect the registry.
// Components are cleaned (invalid entries removed) during iteration.
//
// Thread-safe: Can be called concurrently.
ComponentList() map[string]Component
// ComponentWalk iterates over all registered components.
//
// Parameters:
// - fct: Callback function called for each component
//
// The iteration can be stopped early by returning false from the callback.
// Invalid components are automatically removed during iteration.
//
// Example:
//
// cfg.ComponentWalk(func(key string, cpt Component) bool {
// if cpt.IsRunning() {
// fmt.Printf("%s is running\n", key)
// }
// return true
// })
//
// Thread-safe: Can be called concurrently.
ComponentWalk(fct ComponentListWalkFunc)
// ComponentKeys returns the keys of all registered components.
//
// Returns:
// - []string: Slice of component keys (order not guaranteed)
//
// Invalid components are automatically removed during enumeration.
//
// Thread-safe: Can be called concurrently.
ComponentKeys() []string
// ComponentStart starts all registered components in dependency order.
// This is the internal method called by Config.Start().
//
// Behavior:
// - Resolves dependencies via topological sort
// - Starts components in dependency order
// - Logs start operations if logger is available
// - Stops on first error (remaining components not started)
// - Verifies each component reports started state after Start()
//
// Returns:
// - error: Aggregated error if any component fails to start
//
// Components are started sequentially, not in parallel.
ComponentStart() error
// ComponentIsStarted checks if at least one component is started.
//
// Returns:
// - bool: true if any component reports IsStarted() == true
//
// Used to determine if the application has been initialized.
//
// Thread-safe: Can be called concurrently.
ComponentIsStarted() bool
// ComponentReload reloads all registered components in dependency order.
// This is the internal method called by Config.Reload().
//
// Behavior:
// - Reloads components in dependency order
// - Logs reload operations if logger is available
// - Stops on first error (remaining components not reloaded)
// - Verifies each component still reports started state after Reload()
//
// Returns:
// - error: Aggregated error if any component fails to reload
//
// Components should implement hot-reload without full restart.
ComponentReload() error
// ComponentStop stops all registered components in reverse dependency order.
// This is the internal method called by Config.Stop().
//
// Behavior:
// - Stops components in reverse dependency order
// - Best-effort shutdown (does not propagate errors)
// - Each component's Stop() is called sequentially
//
// This method does not return errors; all components must stop cleanly.
ComponentStop()
// ComponentIsRunning checks the running state of components.
//
// Parameters:
// - atLeast: If true, returns true if at least one component is running.
// If false, returns true only if all components are running.
//
// Returns:
// - bool: Running state based on atLeast parameter
//
// Example:
//
// // Check if any component is running
// if cfg.ComponentIsRunning(true) {
// fmt.Println("At least one component is running")
// }
//
// // Check if all components are running
// if cfg.ComponentIsRunning(false) {
// fmt.Println("All components are running")
// }
//
// Thread-safe: Can be called concurrently.
ComponentIsRunning(atLeast bool) bool
// DefaultConfig generates a default configuration file from all components.
//
// Returns:
// - io.Reader: JSON configuration containing default values from all components
//
// The generated JSON structure has each component's config under its key:
//
// {
// "database": {
// "host": "localhost",
// "port": 5432
// },
// "cache": {
// "ttl": 300
// }
// }
//
// Components without default config are omitted.
// The JSON is properly formatted and compacted.
//
// Thread-safe: Can be called concurrently.
DefaultConfig() io.Reader
// RegisterFlag registers command-line flags for all components.
//
// Parameters:
// - Command: The cobra command to register flags with
//
// Returns:
// - error: Aggregated error if any component fails flag registration
//
// This delegates to each component's RegisterFlag() method.
// Typically called during CLI initialization before parsing flags.
//
// Thread-safe: Can be called concurrently.
RegisterFlag(Command *spfcbr.Command) error
}
ComponentList provides component registry management operations. This interface is embedded in the Config interface to provide component registration, retrieval, lifecycle management, and configuration generation.
The registry is thread-safe and supports:
- Dynamic component registration and removal
- Dependency-ordered lifecycle operations
- Configuration aggregation from all components
- Component enumeration and inspection
type ComponentListWalkFunc ¶
ComponentListWalkFunc is a callback function type for iterating over components. It receives the component key and component instance for each registered component.
Parameters:
- key: The unique identifier for the component
- cpt: The component instance
Returns:
- bool: Return true to continue iteration, false to stop early
Example:
cfg.ComponentWalk(func(key string, cpt Component) bool {
fmt.Printf("Component %s: %s\n", key, cpt.Type())
return true // Continue to next component
})
type ComponentMonitor ¶
type ComponentMonitor interface {
// RegisterMonitorPool registers a monitor pool provider function.
// The component can use this to register health checks, metrics, and status endpoints.
// This method is called during the component's initialization (Init).
//
// The monitor pool typically provides:
// - Health check registration.
// - Metrics collection.
// - Status reporting.
//
// Components should store this function and call it when they are ready to register monitors.
RegisterMonitorPool(p montps.FuncPool)
// GetMonitorNames returns a slice of strings containing the unique names of all
// monitors that have been registered by this component.
//
// This function is crucial for systems that need to dynamically discover and
// interact with the health checks or metrics associated with a component. For example,
// a status reporting system might use this method to fetch the names of all
// relevant monitors and then query their individual statuses.
//
// A component can register multiple monitors, each with a unique name. This method
// should return all of them. If a component does not register any monitors, it
// should return an empty or nil slice.
//
// Example Usage:
//
// // A status package could use this to dynamically build a list of mandatory checks.
// component := config.ComponentGet("my-database-component")
// if componentWithMonitors, ok := component.(types.ComponentMonitor); ok {
// monitorNames := componentWithMonitors.GetMonitorNames()
// // monitorNames might be: []string{"db_connection_pool", "db_query_latency"}
// status.AddMandatoryChecks(monitorNames...)
// }
//
// Returns:
// A slice of strings, where each string is the name of a monitor.
GetMonitorNames() []string
}
ComponentMonitor provides health check and metrics integration for components. Components implementing this interface can register monitors for observability.
type ComponentViper ¶
type ComponentViper interface {
// RegisterFlag registers command-line flags for the component.
// These flags are typically bound to Viper keys for configuration loading.
// The 'key' parameter (from the Init method) can be used to namespace flags.
//
// Example:
// cmd.Flags().String("database.host", "localhost", "Database host")
// viper.BindPFlag("database.host", cmd.Flags().Lookup("database.host"))
//
// It returns an error if flag registration fails.
RegisterFlag(Command *spfcbr.Command) error
}
ComponentViper provides Viper configuration integration for components. Components implementing this interface can register command-line flags that are automatically bound to Viper configuration keys.
type FuncCptEvent ¶
FuncCptEvent is a function type for component lifecycle event hooks. It is called before and after component lifecycle operations (e.g., Start, Reload). The function receives the component instance and returns an error if the hook fails.
type FuncCptGet ¶
FuncCptGet is a function type that retrieves a component by its key. It is used by components to access other components via dependency injection. It returns nil if the component with the given key does not exist.