Documentation
¶
Overview ¶
Package run implements an actor-runner with deterministic teardown. It uses the concepts found in the https://github.com/oklog/run/ package as its basis and enhances it with configuration registration and validation as well as pre-run phase logic.
Index ¶
- Constants
- func AddPath(path string)
- func ParseConfig(args ...string) error
- func RegisterConfig(configStructure Config, opts ...ConfigOption) error
- func SetExtensionOrder(ext []string)
- func SetFileReader(fr FileReader)
- func SetHelpText(helpText string)
- type Config
- type ConfigErrorManager
- type ConfigManager
- type ConfigOption
- type Error
- type FileReader
- type Group
- type Initializer
- type Namer
- type OSFileReader
- type PreRunner
- type Service
- type StringFileReader
- type UsageProvider
Constants ¶
const BinaryName = "{{.Name}}"
BinaryName holds the template variable that will be replaced by the Group name in HelpText strings.
Variables ¶
This section is empty.
Functions ¶
func AddPath ¶
func AddPath(path string)
AddPath adds a directory path to search for the registered configuration files.
func ParseConfig ¶
ParseConfig parses the registered configuration structures, setting up command-line flags, environment variables, as well as loading configuration from a file if applicable. Defaults from the struct fields are used where no other value is provided.
Order of precedence (lowest to highest): 1. Struct field defaults (already set before registration) 2. Configuration file 3. Environment variables 4. Command-line flags
Errors encountered during parsing are returned.
func RegisterConfig ¶
func RegisterConfig(configStructure Config, opts ...ConfigOption) error
RegisterConfig registers a new Config instance and its provided configuration structure.
func SetExtensionOrder ¶
func SetExtensionOrder(ext []string)
SetExtensionOrder provides the extension name search order for configuration files. By default, the following order exists: yaml, yml, json.
func SetFileReader ¶
func SetFileReader(fr FileReader)
SetFileReader sets the FileReader to use for loading configuration files.
func SetHelpText ¶
func SetHelpText(helpText string)
Types ¶
type Config ¶
type Config interface {
// Validate should validate the parameters after all configuration has been
// loaded. It will be provided with a ConfigErrorManager implementation to
// provide the AddError method for returning errors tied to
// specific properties as they are registered with the provided underlying
// ConfigManager.
Validate(ConfigErrorManager)
}
Config interface required to implement a run config compatible configuration struct.
func ConfigWithOptions ¶
func ConfigWithOptions(c Config, o ...ConfigOption) Config
ConfigWithOptions enables a Config object to participate in a Group managed application and provide ConfigOptions needed for proper registration with the Group's internal ConfigManager.
type ConfigErrorManager ¶
ConfigErrorManager interface provides a method for returning configuration errors tied to specific properties. This interface is provided to the Config Validate method. The propertyPtr parameter should be a pointer to the property within the Config struct that caused the error.
type ConfigManager ¶
type ConfigManager interface {
// SetFileReader sets the FileReader implementation to use for reading
// configuration files. By default, the standard os package is used.
SetFileReader(fr FileReader)
// AddPath adds a directory path to search for the registered configuration files.
AddPath(path string)
// SetExtensionOrder provides the extension name search order for configuration files.
// By default, the following order exists: yaml, yml, json.
SetExtensionOrder(ext []string)
// SetHelpText sets the help text displayed when requesting help for
// configuration options.
SetHelpText(helpText string)
// RegisterConfig registers a new Config instance and its provided configuration
// structure.
RegisterConfig(configStructure Config, opts ...ConfigOption) error
// ParseConfig parses the registered configuration structures, setting up
// command-line flags, environment variables as well as loading configuration
// from a file if applicable. Defaults from the struct fields are used where no
// other value is provided.
//
// Order of precedence (lowest to highest):
// 1. Struct field defaults (already set before registration)
// 2. Configuration file
// 3. Environment variables
// 4. Command-line flags
//
// Errors encountered during parsing are returned.
ParseConfig(args ...string) error
}
ConfigManager interface defines the methods for managing configuration using structs implementing the Config interface.
func NewConfigManager ¶
func NewConfigManager() ConfigManager
NewConfigManager creates a new ConfigManager instance with default settings.
type ConfigOption ¶
type ConfigOption func(*config) error
ConfigOption defines a function type for configuration options that can be applied to a config instance.
func WithDefaultCaseStyle ¶
func WithDefaultCaseStyle() ConfigOption
WithDefaultCaseStyle sets the case style to default, meaning that struct field names are lowercased unless overridden by explicit JSON or YAML tags.
func WithExtension ¶
func WithExtension(name string) ConfigOption
WithExtension sets the name of the configuration file extension to look for within the added search paths instead of the default extension search order. This typically is not needed as we have a search order from yaml, yml, json. Use this in case we have the same file name base with different extension deal with different configuration data.
func WithFile ¶
func WithFile(name string) ConfigOption
WithFile sets the name of the configuration file (without the file extension) to look for within the added search paths, unless WithFile provides a fully qualified path to the file. The actual filename must only contain lowercase letters (a-z), numbers, and dots (.). The first and last characters cannot be dots, and dots cannot immediately follow each other. A dot is replaced with a hyphen (-) when used as a command-line flag and with an underscore (_) when used as an environment variable.
func WithFilePathParamName ¶
func WithFilePathParamName(name string, flag, envVar bool) ConfigOption
WithFilePathParamName sets the name of the parameter used to specify the (full) path of the configuration file. The name must only contain lowercase letters (a-z), numbers, and dots (.). The first and last characters cannot be dots, and dots cannot immediately follow each other. A dot is replaced with a hyphen (-) when used as a command-line flag and with an underscore (_) when used as an environment variable. Both flag and environment variable usage can be enabled or disabled via the respective boolean parameters.
func WithKebabCaseStyle ¶
func WithKebabCaseStyle() ConfigOption
WithKebabCaseStyle sets the case style to kebab-case, meaning that struct field names are converted to kebab-case unless overridden by explicit JSON or YAML tags.
func WithSnakeCaseStyle ¶
func WithSnakeCaseStyle() ConfigOption
WithSnakeCaseStyle sets the case style to snake_case, meaning that struct field names are converted to snake_case unless overridden by explicit JSON or YAML tags.
type Error ¶
type Error string
const ( ErrMissingConfigStruct Error = "missing required config structure, config can't be nil" ErrInvalidConfigStruct Error = "invalid config structure, must be a pointer to a struct" ErrDuplicateStructInConfig Error = "duplicate struct instance in same config" ErrDuplicateStructInConfigs Error = "duplicate struct instance across configs" ErrOptionValueInvalid Error = "invalid option value" ErrTagDirectiveInvalid Error = "invalid tag directive" ErrDuplicateFileName Error = "duplicate configuration file name" ErrRootStructDisabled Error = "root struct is disabled with run:\"-\"" ErrRequired Error = "required configuration property" ErrInvalid Error = "invalid configuration property" ErrRanAlready Error = "group run already executed" // ErrBailEarlyRequest is returned when a call to Run was successful but // signals that the application should exit in success immediately. // It is typically returned on --version and --help requests that have been // served. It can and should be used for custom config phase situations where // the job of the application is done. ErrBailEarlyRequest Error = "exit request from flag handler" // ErrRequestedShutdown can be used by Service implementations to gracefully // request a shutdown of the application. Group will then exit without errors. ErrRequestedShutdown Error = "shutdown requested" )
type FileReader ¶
type FileReader interface {
ReadFile(path string) ([]byte, error)
Stat(path string) (os.FileInfo, error)
}
FileReader interface defines the methods for reading files from the file system. This interface can be implemented to provide custom file reading mechanisms, such as reading from embedded files or remote storage.
type Group ¶
type Group struct {
// Name of the Group-managed service. If omitted, the binary name will be
// used as found at runtime.
Name string
// HelpText is optional and allows to provide some additional help context
// when --help is requested.
HelpText string
Logger telemetry.Logger
ConfigManager ConfigManager
// contains filtered or unexported fields
}
Group builds on concepts taken from https://github.com/oklog/run to provide a deterministic way to manage service lifecycles. It allows for easy composition of elegant monoliths as well as adding signal handlers, metrics services, etc.
func (*Group) Deregister ¶
Deregister will inspect the provided modules implementing Group interfaces to see if it needs to deregister the modules for any of the Group bootstrap phases. The returned array of booleans is of the same size as the number of provided modules, signaling for each provided module if it successfully deregistered with Group for at least one of the bootstrap phases. It is generally safe to use Deregister at any bootstrap phase except at Serve time (when it will have no effect). WARNING: Group modules incorporating Config objects can't be deregistered for their Config phase, as they are managed by the ConfigManager and deregistration would cause inconsistencies between the ConfigManager and the Group. However, they will not participate in pre-run or serve phases. WARNING: Dependencies between modules can cause a crash as a dependent module might expect the other module to have gone through all the required bootstrapping phases. This typically is a design flaw and should be avoided by proper isolated module design.
func (*Group) ListModules ¶
ListModules returns a list of all Group phases and the modules registered to each of them.
func (*Group) Register ¶
Register will inspect the provided objects implementing Group interfaces to see if it needs to register the objects for any of the Group bootstrap phases. If a module doesn't satisfy any of the bootstrap phases, it is ignored by Group. The returned array of booleans is of the same size as the number of provided modules. Signaling for each provided module if it successfully registered with Group for at least one of the bootstrap phases or if it was ignored.
func (*Group) Run ¶
Run will execute all phases of all registered modules and blocks until an error occurs.
The following phases are executed in the following sequence:
Initialization phase (serially, in order of module registration)
- Init() Initialize modules supporting this interface.
Config phase (serially, in order of module registration)
- Validate() Validate Config modules. Exit on the first error.
PreRunner phase (serially, in order of module registration)
- PreRun() Execute PreRunner modules. Exit on the first error.
Service phase (concurrently)
- Serve() Execute all Service modules in separate Go routines.
- "wait" Block until one of the Serve() methods returns.
- "shutdown" Cancel the context.Context provided to all the
Service modules registered.
Run will return with the originating error on:
- first Config.Validate() returning an error
- first PreRunner.PreRun() returning an error
- first Service.Serve() returning
Note: it is perfectly acceptable to use Group without Service modules. In this case Run will just return immediately after having handled the Config and PreRunner phases of the registered modules. This is particularly convenient if using the common pkg middlewares in a CLI, script, or other ephemeral environment.
func (*Group) RunAndExit ¶ added in v0.1.3
RunAndExit is a convenience method that runs the Group and exits with code 0 on a graceful shutdown request or with code -1 on any other error. If no services are registered, it will exit with code 0 immediately after successful config and pre-run phases.
type Initializer ¶
type Initializer interface {
Init()
}
Initializer interface should be implemented by Config or Group modules that need to perform initialization before configuration has been parsed and/or any PreRun or Service methods are called.
type Namer ¶
type Namer interface {
Name() string
}
Namer is an optional interface implemented by Config or Group modules to provide a good name for the Unit. This name can be used in various log messages and help texts originating from the run environment. Name should return a short but good identifier of the module.
type OSFileReader ¶
type OSFileReader struct{}
OSFileReader provides a default OS-backed implementation
type PreRunner ¶
type PreRunner interface {
PreRun() error
}
PreRunner interface should be implemented by Group modules that need a pre-run stage before starting the Group Services. If a PreRun returns an error, it will stop the Group immediately.
func NewPreRunner ¶
NewPreRunner takes a name and a standalone pre-runner compatible function and turns them into a Group compatible PreRunner, ready for registration. This function is typically used to wire application concerns together with the registered modules / dependencies.
type Service ¶
type Service interface {
// Serve starts the GroupService and blocks until the provided
// context is canceled.
Serve(ctx context.Context) error
}
Service interface should be implemented by Group modules that need to run a blocking service during the lifetime of the application. If the blocking service returns an error, the Group will stop all services by cancelling the provided context. The Serve method should block until the context is canceled. Modules which need to shut down the application as part of a regular non-error condition (like receiving a shutdown signal) and not as a result of an actual error, should return the run.ErrRequestedShutdown error. The Group will interpret this as a normal shutdown condition and not as an error. Any other error returned by the Serve method should be treated as an actual error condition and will be returned by the Group Run method. Services that need to perform cleanup when the context is canceled should monitor the context's Done channel. When the context is canceled, the Serve method should return nil if no errors are encountered.
type StringFileReader ¶
type StringFileReader struct {
// contains filtered or unexported fields
}
func NewStringFileReader ¶
func NewStringFileReader() *StringFileReader
func (*StringFileReader) AddFile ¶
func (sr *StringFileReader) AddFile(path string, content []byte)
type UsageProvider ¶
UsageProvider is an optional interface that Config structs can implement to provide dynamic usage string overrides for struct properties. When implemented, the Usage() method is called during property registration, and any non-empty usage strings in the returned map will override usage defined in run tags.
The map keys should be pointers to the actual struct fields (e.g., &cfg.FieldName).
Usage precedence (lowest to highest):
- Field name (default)
- run:"usage=..." tag directive
- UsageProvider.Usage() method (highest priority)
Example:
type MyConfig struct {
Name string `run:"usage=Default name usage"`
}
func (c *MyConfig) Usage() map[any]string {
return map[any]string{
&c.Name: "Custom name usage from UsageProvider",
}
}
This is useful when:
- Usage strings need to be generated dynamically
- Help text depends on runtime conditions
- Usage strings are maintained separately from struct tags
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
pkg
|
|
|
json
Package json provides JSON marshal/unmarshal functions with custom naming conventions.
|
Package json provides JSON marshal/unmarshal functions with custom naming conventions. |
|
log
Package log holds a minimal implementation of telemetry.Logging
|
Package log holds a minimal implementation of telemetry.Logging |
|
signal
Package signal implements a run.GroupService handling incoming unix signals.
|
Package signal implements a run.GroupService handling incoming unix signals. |
|
strcase
Package strcase provides string case conversion utilities.
|
Package strcase provides string case conversion utilities. |
|
test
Package test adds helper utilities for testing run.Group enabled services.
|
Package test adds helper utilities for testing run.Group enabled services. |
|
version
Package version can be used to implement embedding versioning details from git branches and tags into the binary importing this package.
|
Package version can be used to implement embedding versioning details from git branches and tags into the binary importing this package. |
|
yaml
Package yaml provides YAML marshal/unmarshal functions with custom naming conventions.
|
Package yaml provides YAML marshal/unmarshal functions with custom naming conventions. |