framework

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 1, 2025 License: MIT Imports: 30 Imported by: 0

Documentation

Overview

Package framework provides the core application lifecycle management for Forge microservices.

The framework package implements Clean Architecture principles with a component-based design that enables building production-ready microservices with built-in observability, health checks, graceful shutdown, and lifecycle management.

Basic Usage

Create a service by implementing the Component interface and using the App builder:

cfg := config.DefaultBaseConfig()
cfg.ServiceName = "my-service"

myComponent := &MyComponent{}

app, err := framework.New(
	framework.WithConfig(&cfg),
	framework.WithVersion("1.0.0"),
	framework.WithComponent(myComponent),
)
if err != nil {
	log.Fatal(err)
}

if err := app.Run(context.Background()); err != nil {
	log.Fatal(err)
}

Architecture

The framework follows Clean Architecture with these key concepts:

  • Components: Your business logic implementing Component interface
  • Bundles: Pre-built integrations (PostgreSQL, Redis, etc.)
  • App: Main application orchestrating lifecycle and dependencies
  • Health: Comprehensive health check system with liveness/readiness
  • Observability: Built-in OpenTelemetry tracing and metrics

Lifecycle Management

The App handles sophisticated startup and shutdown orchestration:

  1. Initialize observability (tracing, metrics)
  2. Initialize bundles in registration order
  3. Execute startup hooks
  4. Start gRPC and HTTP servers
  5. Start components in registration order
  6. Mark service as ready

Shutdown happens in reverse order with proper timeout handling and graceful termination.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewHealthLogger

func NewHealthLogger(logging *LoggingManager) *healthLoggerAdapter

NewHealthLogger creates a logger adapter for the health system.

Types

type App

type App struct {
	// contains filtered or unexported fields
}

App represents the main service application with lifecycle management. App orchestrates the entire application lifecycle including initialization, startup, runtime, and graceful shutdown of all registered components and services.

The App follows a sophisticated startup sequence:

  1. Configuration validation
  2. Logging and observability initialization
  3. Bundle initialization (in registration order)
  4. Startup hook execution
  5. gRPC and HTTP server startup
  6. Component startup (in registration order)
  7. Health check registration and readiness marking

Shutdown happens in reverse order with proper timeout handling. The App ensures all resources are cleaned up gracefully on termination.

func New

func New(options ...AppOption) (*App, error)

New creates a new service application with the given options.

func (*App) Config

func (a *App) Config() *config.BaseConfig

Config returns the application configuration.

func (*App) HealthRegistry

func (a *App) HealthRegistry() *forgeHealth.Registry

HealthRegistry returns the health registry.

func (*App) IsRunning

func (a *App) IsRunning() bool

IsRunning returns true if the application is running.

func (*App) IsStopping

func (a *App) IsStopping() bool

IsStopping returns true if the application is in the process of stopping.

func (*App) Logger

func (a *App) Logger() *LoggingManager

Logger returns the logging manager.

func (*App) Run

func (a *App) Run(ctx context.Context) error

Run starts the application and blocks until shutdown.

func (*App) Start

func (a *App) Start(ctx context.Context) error

Start starts all application components.

func (*App) Stop

func (a *App) Stop(ctx context.Context) error

Stop stops all application components gracefully using the shutdown orchestrator.

func (*App) Uptime

func (a *App) Uptime() time.Duration

Uptime returns how long the service has been running.

type AppOption

type AppOption func(*App) error

AppOption configures the App during creation.

func WithBundle

func WithBundle(bundle Bundle) AppOption

WithBundle adds a bundle to the application.

func WithComponent

func WithComponent(component Component) AppOption

WithComponent adds a component to be managed by the app.

func WithConfig

func WithConfig(config *config.BaseConfig) AppOption

WithConfig sets the base configuration.

func WithGRPCRegistrar

func WithGRPCRegistrar(registrar Registrar) AppOption

WithGRPCRegistrar adds a gRPC service registrar.

func WithHealthContributor

func WithHealthContributor(contributor HealthContributor) AppOption

WithHealthContributor adds health checks from a contributor.

func WithShutdownHook

func WithShutdownHook(hook ShutdownHook) AppOption

WithShutdownHook adds a shutdown hook.

func WithStartupHook

func WithStartupHook(hook StartupHook) AppOption

WithStartupHook adds a startup hook.

func WithStreamInterceptor

func WithStreamInterceptor(interceptor grpc.StreamServerInterceptor) AppOption

WithStreamInterceptor adds a gRPC stream server interceptor.

func WithUnaryInterceptor

func WithUnaryInterceptor(interceptor grpc.UnaryServerInterceptor) AppOption

WithUnaryInterceptor adds a gRPC unary server interceptor.

func WithVersion

func WithVersion(version string) AppOption

WithVersion sets the service version.

type Bundle

type Bundle interface {
	// Name returns a unique identifier for this bundle.
	Name() string

	// Initialize sets up the bundle's functionality within the application.
	// This method is called during application startup before components are started.
	Initialize(app *App) error

	// Stop gracefully shuts down the bundle and cleans up resources.
	// This method is called during application shutdown in reverse initialization order.
	// Bundles should respect the context deadline for graceful termination.
	Stop(ctx context.Context) error
}

Bundle represents a reusable collection of functionality that can be added to an app. Bundles encapsulate common integrations like database connections, message queues, monitoring, etc. They are initialized in registration order during startup and stopped in reverse order during shutdown.

Example bundle for PostgreSQL integration:

type PostgreSQLBundle struct {
	config *DatabaseConfig
	db     *sql.DB
}

func (b *PostgreSQLBundle) Name() string {
	return "postgresql"
}

func (b *PostgreSQLBundle) Initialize(app *App) error {
	db, err := sql.Open("postgres", b.config.URL)
	if err != nil {
		return err
	}
	b.db = db
	return nil
}

func (b *PostgreSQLBundle) Stop(ctx context.Context) error {
	if b.db != nil {
		return b.db.Close()
	}
	return nil
}

type Component

type Component interface {
	// Start initializes the component and starts any background processes.
	// This method is called during application startup after all bundles
	// have been initialized and servers have been started.
	Start(ctx context.Context) error

	// Stop gracefully shuts down the component and cleans up resources.
	// This method is called during application shutdown with a timeout context.
	// Components should respect the context deadline for graceful termination.
	Stop(ctx context.Context) error
}

Component represents a service component that can be started and stopped. Components are the primary way to integrate your business logic with the Forge framework.

Components are started in registration order during application startup and stopped in reverse order during graceful shutdown. Each component should handle its own resource management and cleanup.

Example implementation:

type UserService struct {
	db *sql.DB
}

func (s *UserService) Start(ctx context.Context) error {
	// Initialize connections, start background workers, etc.
	return s.db.PingContext(ctx)
}

func (s *UserService) Stop(ctx context.Context) error {
	// Clean up resources, stop workers, close connections
	return s.db.Close()
}

type HTTPServerBuilder

type HTTPServerBuilder struct {
	// contains filtered or unexported fields
}

HTTPServerBuilder builds an enhanced HTTP server with configurable endpoints.

func NewHTTPServerBuilder

func NewHTTPServerBuilder(app *App, config HTTPServerConfig) *HTTPServerBuilder

NewHTTPServerBuilder creates a new HTTP server builder.

func (*HTTPServerBuilder) Build

func (b *HTTPServerBuilder) Build() *http.Server

Build constructs the HTTP server with all configured endpoints and middleware.

type HTTPServerConfig

type HTTPServerConfig struct {
	// CORS configuration
	EnableCORS      bool     `yaml:"enable_cors" env:"ENABLE_CORS"`
	CORSOrigins     []string `yaml:"cors_origins" env:"CORS_ORIGINS"`
	CORSMethods     []string `yaml:"cors_methods" env:"CORS_METHODS"`
	CORSHeaders     []string `yaml:"cors_headers" env:"CORS_HEADERS"`
	CORSCredentials bool     `yaml:"cors_credentials" env:"CORS_CREDENTIALS"`

	// Endpoint configuration
	EnableMetrics    bool   `yaml:"enable_metrics" env:"ENABLE_METRICS"`
	MetricsPath      string `yaml:"metrics_path" env:"METRICS_PATH"`
	HealthPathPrefix string `yaml:"health_path_prefix" env:"HEALTH_PATH_PREFIX"`

	// Request logging
	EnableRequestLogging bool `yaml:"enable_request_logging" env:"ENABLE_REQUEST_LOGGING"`
	LogRequestBody       bool `yaml:"log_request_body" env:"LOG_REQUEST_BODY"`
	LogResponseBody      bool `yaml:"log_response_body" env:"LOG_RESPONSE_BODY"`
}

HTTPServerConfig contains configuration for the HTTP server endpoints.

func DefaultHTTPServerConfig

func DefaultHTTPServerConfig() HTTPServerConfig

DefaultHTTPServerConfig returns HTTP server configuration with sensible defaults.

func (*HTTPServerConfig) Validate

func (c *HTTPServerConfig) Validate() error

Validate performs comprehensive validation on HTTP server configuration.

type HealthContributor

type HealthContributor interface {
	// HealthChecks returns a slice of health checks that this component provides.
	// These checks will be automatically registered during application startup.
	HealthChecks() []forgeHealth.Check
}

HealthContributor represents a service that contributes health checks. Components implementing this interface can provide health checks that will be automatically registered with the health registry.

Example:

func (s *UserService) HealthChecks() []health.Check {
	return []forgeHealth.Check{
		forgeHealth.NewBasicCheck(
			forgeHealth.DefaultCheckConfig("database"),
			func(ctx context.Context) error {
				return s.db.PingContext(ctx)
			},
			func(ctx context.Context) error {
				return s.db.PingContext(ctx)
			},
		),
	}
}

type LoggingManager

type LoggingManager struct {
	// contains filtered or unexported fields
}

LoggingManager manages logging configuration and provides logger instances.

func NewLoggingManager

func NewLoggingManager(config *config.BaseConfig) *LoggingManager

NewLoggingManager creates a new logging manager with the given configuration.

func (*LoggingManager) Initialize

func (lm *LoggingManager) Initialize() error

Initialize sets up the logging configuration.

func (*LoggingManager) Logger

func (lm *LoggingManager) Logger() *zerolog.Logger

Logger returns the base logger instance.

func (*LoggingManager) WithContext

func (lm *LoggingManager) WithContext(fields map[string]interface{}) zerolog.Logger

WithContext creates a logger with additional context fields.

func (*LoggingManager) WithService

func (lm *LoggingManager) WithService(service, component string) zerolog.Logger

WithService creates a logger with service and component context.

type ObservabilityConfig

type ObservabilityConfig struct {
	ServiceName    string
	ServiceVersion string
	Environment    string
	OTELEndpoint   string
	SampleRate     float64
}

ObservabilityConfig contains configuration for observability (tracing, metrics).

func NewObservabilityConfig

func NewObservabilityConfig(baseConfig *config.BaseConfig, version string) *ObservabilityConfig

NewObservabilityConfig creates a new observability config from base config.

type ObservabilityManager

type ObservabilityManager struct {
	// contains filtered or unexported fields
}

ObservabilityManager manages OpenTelemetry tracing and metrics.

func NewObservabilityManager

func NewObservabilityManager(config *ObservabilityConfig) *ObservabilityManager

NewObservabilityManager creates a new observability manager.

func (*ObservabilityManager) GetMeter

func (om *ObservabilityManager) GetMeter(name string) otelmetric.Meter

GetMeter returns a meter for the given name.

func (*ObservabilityManager) GetTracer

func (om *ObservabilityManager) GetTracer(name string) oteltrace.Tracer

GetTracer returns a tracer for the given name.

func (*ObservabilityManager) Initialize

func (om *ObservabilityManager) Initialize(ctx context.Context) error

Initialize sets up OpenTelemetry tracing and metrics.

func (*ObservabilityManager) Shutdown

func (om *ObservabilityManager) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down the observability components.

type OrchestrationHook

type OrchestrationHook struct {
	Name string
	Func ShutdownHookFunc
}

OrchestrationHook represents a named shutdown hook with a cleanup function.

func ComponentShutdownHook

func ComponentShutdownHook(name string, component Component) OrchestrationHook

ComponentShutdownHook creates a shutdown hook for a Component.

type Registrar

type Registrar interface {
	// RegisterGRPC registers gRPC service handlers with the provided server.
	// This method is called during application startup before the gRPC server starts.
	RegisterGRPC(server *grpc.Server) error
}

Registrar represents a service that can register gRPC handlers. Components that expose gRPC services should implement this interface to register their handlers with the framework's gRPC server.

Example:

func (s *UserService) RegisterGRPC(server *grpc.Server) error {
	userpb.RegisterUserServiceServer(server, s)
	return nil
}

type ShutdownHook

type ShutdownHook func(ctx context.Context, app *App) error

ShutdownHook is called during application shutdown. Use shutdown hooks for custom cleanup logic that needs to run before components are stopped. Hooks are executed in reverse registration order.

type ShutdownHookFunc

type ShutdownHookFunc func(ctx context.Context) error

ShutdownHookFunc is a function that performs cleanup during shutdown.

type ShutdownOrchestrator

type ShutdownOrchestrator struct {
	// contains filtered or unexported fields
}

ShutdownOrchestrator manages the graceful shutdown of service components.

func NewShutdownOrchestrator

func NewShutdownOrchestrator(timeout time.Duration) *ShutdownOrchestrator

NewShutdownOrchestrator creates a new shutdown orchestrator with the given timeout.

func (*ShutdownOrchestrator) RegisterHook

func (so *ShutdownOrchestrator) RegisterHook(name string, hookFunc ShutdownHookFunc)

RegisterHook adds a shutdown hook to be executed during shutdown. Hooks are executed in the order they were registered.

func (*ShutdownOrchestrator) RegisterHookWithTimeout

func (so *ShutdownOrchestrator) RegisterHookWithTimeout(name string, timeout time.Duration, hookFunc ShutdownHookFunc)

RegisterHookWithTimeout adds a shutdown hook with a specific timeout.

func (*ShutdownOrchestrator) Shutdown

func (so *ShutdownOrchestrator) Shutdown(ctx context.Context) error

Shutdown executes all registered hooks in order and waits for completion. Returns an error if any hook fails or if the overall timeout is exceeded.

type StartupHook

type StartupHook func(ctx context.Context, app *App) error

StartupHook is called during application startup. Use startup hooks for custom initialization logic that needs to run after bundles are initialized but before the service is marked as ready.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL