Files
golib/config/README.md
nabbar 9e8179374b README:
- Add some README file to give missing documentations or update existing documentation file

Package Archive:
- Add some comments to godoc information
- Moving NopWriterCloser interface to ioutils package

Package IOUtils:
- New package NopWriterCloser to implement interfac like NopReader

Package Database:
- KVMap: fix missing function following update of kvdriver

Package Duration:
- Rename BDD testing

Package Context/Gin:
- Moving function New between model & interface file

Package AWS:
- rework Walk function to use more generic with standard walk caller function
- func walk will now no more return and include error (can be catched into the given func)
- func walk will now return a bool to continue or stop the loop
- func walk with many input function will now stop when all given function return false
- func walk will now return error only about main process and not given function

Package errors:
- Add interface error into interface Error

Package IOUtils:
- Moving IOWrapper as subPackage and optimize process + allow thread safe
2025-05-25 06:29:25 +02:00

8.3 KiB

golib/config

This package provides a modular configuration management system for Go applications, supporting dynamic components, context management, lifecycle events, logging, monitoring, and shell integration.

Features

  • Centralized configuration management using Viper.
  • Dynamic components: add, remove, start, stop, reload, and manage dependencies.
  • Context management: cancellation, custom hooks.
  • Lifecycle events: hooks before/after start, reload, stop.
  • Configurable logging.
  • Component monitoring.
  • Integrated shell commands for component control.

Installation

Add to your go.mod:

require github.com/nabbar/golib/config vX.Y.Z

Quick Start

import (
    "github.com/nabbar/golib/config"
    "github.com/nabbar/golib/version"
)

func main() {
    vrs := version.New("1.0.0")
    cfg := config.New(vrs)

    // Register your components here
    // cfg.ComponentSet("myComponent", myComponentInstance)

    // Register hooks, logger, etc.
    // cfg.RegisterFuncStartBefore(func() error { ...; return nil })

    if err := cfg.Start(); err != nil {
        panic(err)
    }

    // ...
    cfg.Shutdown(0)
}

Main Interfaces

  • Config: main interface, see config/interface.go.
  • Component: to implement for each component, see config/types/component.go.

Lifecycle Methods

  • Start() error: starts all registered components respecting dependencies.
  • Reload() error: reloads configuration and components.
  • Stop(): stops all components cleanly.
  • Shutdown(code int): stops everything and exits the process.

Component Management

  • ComponentSet(key, cpt): register a component.
  • ComponentGet(key): retrieve a component.
  • ComponentDel(key): remove a component.
  • ComponentList(): get all components.
  • ComponentStart(), ComponentStop(), ComponentReload(): global actions.

Event Hooks

Register functions to be called before/after each lifecycle step:

cfg.RegisterFuncStartBefore(func() error { /* ... */ return nil })
cfg.RegisterFuncStopAfter(func() error { /* ... */ return nil })
cfg.RegisterFuncReloadBefore(func() error { /* ... */ return nil })
cfg.RegisterFuncReloadAfter(func() error { /* ... */ return nil })

Context and Cancellation

  • Context(): returns the config context instance.
  • CancelAdd(func()): register custom functions to call on context cancel.
  • CancelClean(): clear all registered cancel functions.

Shell Commands

Expose commands to list, start, stop, and restart components:

cmds := cfg.GetShellCommand()
// Integrate these into your CLI

Available commands:

  • list: list all components
  • start: start components (all or by name)
  • stop: stop components (all or by name)
  • restart: restart components (all or by name)

Signal Handling

Handles system signals (SIGINT, SIGTERM, SIGQUIT) for graceful shutdown via WaitNotify().

Default Configuration Generation

Generate a default configuration (JSON) for all registered components:

r := cfg.DefaultConfig()
// r is an io.Reader containing the default config JSON

Component Interface

To create a component, implement the following interface (see config/types/component.go):

type Component interface {
    Type() string
    Init(key string, ctx libctx.FuncContext, get FuncCptGet, vpr libvpr.FuncViper, vrs libver.Version, log liblog.FuncLog)
    DefaultConfig(indent string) []byte
    Dependencies() []string
    SetDependencies(d []string) error
    RegisterFlag(Command *spfcbr.Command) error
    RegisterMonitorPool(p montps.FuncPool)
    RegisterFuncStart(before, after FuncCptEvent)
    RegisterFuncReload(before, after FuncCptEvent)
    IsStarted() bool
    IsRunning() bool
    Start() error
    Reload() error
    Stop()
}

Creating a Config Component

This guide explains how to implement a new config component for the golib/config system. Components are modular units that can be registered, started, stopped, reloaded, and monitored within the configuration framework.

1. Component Structure

A component should implement the Component interface, which defines lifecycle methods, dependency management, configuration, and monitoring hooks.

Example structure:

type componentMyType struct {
    x libctx.Config[uint8]      // Context and config storage
    // Add your own fields here (atomic values, state, etc.)
}

2. Implementing the Interface

Implement the following methods:

  • Type() string: Returns the component type name.
  • Init(key, ctx, get, vpr, vrs, log): Initializes the component with its key, context, dependency getter, viper, version, and logger.
  • DefaultConfig(indent string) []byte: Returns the default configuration as JSON (or other format).
  • Dependencies() []string: Lists required component dependencies.
  • SetDependencies(d []string) error: Sets dependencies.
  • RegisterFlag(cmd *cobra.Command) error: Registers CLI flags.
  • RegisterMonitorPool(fct montps.FuncPool): Registers a monitor pool for health/metrics.
  • RegisterFuncStart(before, after FuncCptEvent): Registers hooks for start events.
  • RegisterFuncReload(before, after FuncCptEvent): Registers hooks for reload events.
  • IsStarted() bool: Returns true if started.
  • IsRunning() bool: Returns true if running.
  • Start() error: Starts the component.
  • Reload() error: Reloads the component.
  • Stop(): Stops the component.

3. Configuration Handling

  • Use Viper for configuration loading.
  • Implement a method to unmarshal and validate the config section for your component.
  • Provide a static default config as a JSON/YAML byte slice.

4. Lifecycle Management

  • Use atomic values or context for thread-safe state.
  • Implement logic for Start, Reload, and Stop to manage resources and state.
  • Use hooks (RegisterFuncStart, RegisterFuncReload) to allow custom logic before/after lifecycle events.

5. Dependency Management

  • Use Dependencies() and SetDependencies() to declare and manage required components (e.g., TLS, logger).
  • Retrieve dependencies using the provided FuncCptGet function.

6. Monitoring Integration

  • Implement RegisterMonitorPool to support health and metrics monitoring.
  • Use the monitor pool to register and manage monitor instances for your component.

7. Example Skeleton

type componentMyType struct {
    x libctx.Config[uint8]
    // Add fields as needed
}

func (o *componentMyType) Type() string { return "mytype" }
func (o *componentMyType) Init(key string, ctx libctx.FuncContext, get cfgtps.FuncCptGet, vpr libvpr.FuncViper, vrs libver.Version, log liblog.FuncLog) {
    o.x.Store( /* ... */ )
}
func (o *componentMyType) DefaultConfig(indent string) []byte { /* ... */ }
func (o *componentMyType) Dependencies() []string { /* ... */ }
func (o *componentMyType) SetDependencies(d []string) error { /* ... */ }
func (o *componentMyType) RegisterFlag(cmd *cobra.Command) error { /* ... */ }
func (o *componentMyType) RegisterMonitorPool(fct montps.FuncPool) { /* ... */ }
func (o *componentMyType) RegisterFuncStart(before, after cfgtps.FuncCptEvent) { /* ... */ }
func (o *componentMyType) RegisterFuncReload(before, after cfgtps.FuncCptEvent) { /* ... */ }
func (o *componentMyType) IsStarted() bool { /* ... */ }
func (o *componentMyType) IsRunning() bool { /* ... */ }
func (o *componentMyType) Start() error { /* ... */ }
func (o *componentMyType) Reload() error { /* ... */ }
func (o *componentMyType) Stop() { /* ... */ }

8. Registration

Register your component with the config system:

cfg.ComponentSet("myComponentKey", myComponentInstance)

9. Error Handling

  • Define error codes and messages for your component.
  • Return errors using the liberr.Error type for consistency.

Note:

  • Use atomic values for thread safety.
  • Always validate configuration before starting the component.
  • Integrate logging and monitoring as needed.
  • Follow the modular and decoupled design to ensure maintainability and testability.
  • Consider using context for cancellation and timeouts in long-running operations.
  • Ensure proper cleanup in the Stop method to release resources gracefully.