Documentation
¶
Overview ¶
Package controls provides a lifecycle controller for managing concurrent, long-running services such as HTTP servers, background workers, and schedulers.
The Controller orchestrates startup, health monitoring, and graceful shutdown with proper cleanup ordering. Shared communication channels carry errors, OS signals, and control messages between registered services.
The Controllable interface abstracts the controller for testing, exposing Start, Stop, IsRunning, IsStopped, IsStopping, Register, and configuration methods. Concrete transports are provided by the grpc and http sub-packages.
Index ¶
- Constants
- Variables
- type ChannelProvider
- type CheckResult
- type CheckStatus
- type CheckType
- type Configurable
- type Controllable
- type Controller
- func (c *Controller) Errors() chan error
- func (c *Controller) GetCheckResult(name string) (CheckResult, bool)
- func (c *Controller) GetContext() context.Context
- func (c *Controller) GetLogger() logger.Logger
- func (c *Controller) GetServiceInfo(name string) (ServiceInfo, bool)
- func (c *Controller) GetState() State
- func (c *Controller) Health() chan HealthMessage
- func (c *Controller) IsRunning() bool
- func (c *Controller) IsStopped() bool
- func (c *Controller) IsStopping() bool
- func (c *Controller) Liveness() HealthReport
- func (c *Controller) Messages() chan Message
- func (c *Controller) Readiness() HealthReport
- func (c *Controller) Register(id string, opts ...ServiceOption)
- func (c *Controller) RegisterHealthCheck(check HealthCheck) error
- func (c *Controller) SetErrorsChannel(errs chan error)
- func (c *Controller) SetHealthChannel(health chan HealthMessage)
- func (c *Controller) SetLogger(l logger.Logger)
- func (c *Controller) SetMessageChannel(messages chan Message)
- func (c *Controller) SetShutdownTimeout(d time.Duration)
- func (c *Controller) SetSignalsChannel(signals chan os.Signal)
- func (c *Controller) SetState(state State)
- func (c *Controller) SetWaitGroup(wg *sync.WaitGroup)
- func (c *Controller) Signals() chan os.Signal
- func (c *Controller) Start()
- func (c *Controller) Status() HealthReport
- func (c *Controller) Stop()
- func (c *Controller) Wait()
- func (c *Controller) WaitGroup() *sync.WaitGroup
- type ControllerOpt
- type HealthCheck
- type HealthCheckReporter
- type HealthMessage
- type HealthReport
- type HealthReporter
- type Message
- type ProbeFunc
- type RestartPolicy
- type Runner
- type Service
- type ServiceInfo
- type ServiceOption
- type ServiceStatus
- type Services
- type StartFunc
- type State
- type StateAccessor
- type StatusFunc
- type StopFunc
- type ValidErrorFunc
Examples ¶
Constants ¶
const DefaultShutdownTimeout = 5 * time.Second
DefaultShutdownTimeout is the time allowed for graceful shutdown before services are force-stopped.
Variables ¶
var ErrShutdown = errors.New("controller shutdown")
ErrShutdown is the cause attached to the controller context when a graceful shutdown is initiated. Callers can distinguish a controlled stop from an upstream cancellation via context.Cause(ctx) == controls.ErrShutdown.
Functions ¶
This section is empty.
Types ¶
type ChannelProvider ¶
type ChannelProvider interface {
Messages() chan Message
Health() chan HealthMessage
Errors() chan error
Signals() chan os.Signal
}
ChannelProvider provides access to controller channels.
type CheckResult ¶ added in v1.8.0
type CheckResult struct {
// Status is the health status.
Status CheckStatus
// Message provides human-readable detail about the check result.
Message string
// Timestamp is when this result was produced.
Timestamp time.Time
}
CheckResult represents the outcome of a health check.
type CheckStatus ¶ added in v1.8.0
type CheckStatus int
CheckStatus represents the health state of a check.
const ( // CheckHealthy indicates the check passed. CheckHealthy CheckStatus = iota // CheckDegraded indicates the check passed but with warnings. // Maps to OverallHealthy: true with Status: "DEGRADED". CheckDegraded // CheckUnhealthy indicates the check failed. // Maps to OverallHealthy: false with Status: "ERROR". CheckUnhealthy )
type CheckType ¶ added in v1.8.0
type CheckType int
CheckType determines which health endpoint(s) a check contributes to.
type Configurable ¶
type Configurable interface {
SetErrorsChannel(errs chan error)
SetMessageChannel(control chan Message)
SetSignalsChannel(sigs chan os.Signal)
SetHealthChannel(health chan HealthMessage)
SetWaitGroup(wg *sync.WaitGroup)
SetShutdownTimeout(d time.Duration)
SetLogger(l logger.Logger)
}
Configurable provides controller configuration setters.
type Controllable ¶
type Controllable interface {
Runner
HealthReporter
StateAccessor
Configurable
ChannelProvider
}
Controllable is the full controller interface, composed of all role-based interfaces. Prefer using the narrower interfaces (Runner, HealthReporter, Configurable, etc.) where possible.
type Controller ¶
type Controller struct {
// contains filtered or unexported fields
}
Controller orchestrates the lifecycle of registered services: startup ordering, health monitoring, graceful shutdown, and signal handling.
func NewController ¶
func NewController(ctx context.Context, opts ...ControllerOpt) *Controller
NewController creates a Controller with the given context and options. By default, it registers SIGINT and SIGTERM handlers for graceful shutdown. Use WithoutSignals to disable signal handling (useful in tests).
Example ¶
package main
import (
"context"
"fmt"
"time"
"github.com/phpboyscout/go-tool-base/pkg/controls"
)
func main() {
ctx := context.Background()
// Create a controller (WithoutSignals for non-daemon usage)
controller := controls.NewController(ctx, controls.WithoutSignals())
// Register an HTTP service
controller.Register("http-api",
controls.WithStart(func(ctx context.Context) error {
fmt.Println("HTTP server starting")
return nil
}),
controls.WithStop(func(ctx context.Context) {
fmt.Println("HTTP server stopping")
}),
controls.WithStatus(func() error {
return nil // healthy
}),
)
// Start all services
controller.Start()
// Graceful shutdown
time.Sleep(10 * time.Millisecond)
controller.Stop()
controller.Wait()
}
Output:
func (*Controller) Errors ¶
func (c *Controller) Errors() chan error
func (*Controller) GetCheckResult ¶ added in v1.8.0
func (c *Controller) GetCheckResult(name string) (CheckResult, bool)
GetCheckResult returns the latest result for a named health check.
func (*Controller) GetContext ¶
func (c *Controller) GetContext() context.Context
func (*Controller) GetLogger ¶
func (c *Controller) GetLogger() logger.Logger
func (*Controller) GetServiceInfo ¶ added in v1.6.0
func (c *Controller) GetServiceInfo(name string) (ServiceInfo, bool)
GetServiceInfo returns the runtime information and statistics for a specific service.
func (*Controller) GetState ¶
func (c *Controller) GetState() State
func (*Controller) Health ¶
func (c *Controller) Health() chan HealthMessage
func (*Controller) IsRunning ¶
func (c *Controller) IsRunning() bool
func (*Controller) IsStopped ¶
func (c *Controller) IsStopped() bool
func (*Controller) IsStopping ¶
func (c *Controller) IsStopping() bool
func (*Controller) Liveness ¶ added in v1.6.0
func (c *Controller) Liveness() HealthReport
Liveness returns an aggregate liveness report for all registered services and health checks.
func (*Controller) Messages ¶
func (c *Controller) Messages() chan Message
func (*Controller) Readiness ¶ added in v1.6.0
func (c *Controller) Readiness() HealthReport
Readiness returns an aggregate readiness report for all registered services and health checks.
func (*Controller) Register ¶
func (c *Controller) Register(id string, opts ...ServiceOption)
func (*Controller) RegisterHealthCheck ¶ added in v1.8.0
func (c *Controller) RegisterHealthCheck(check HealthCheck) error
RegisterHealthCheck adds a standalone health check to the controller. Must be called before Start(). The check name must be unique across both services and health checks.
func (*Controller) SetErrorsChannel ¶
func (c *Controller) SetErrorsChannel(errs chan error)
func (*Controller) SetHealthChannel ¶
func (c *Controller) SetHealthChannel(health chan HealthMessage)
func (*Controller) SetLogger ¶
func (c *Controller) SetLogger(l logger.Logger)
func (*Controller) SetMessageChannel ¶
func (c *Controller) SetMessageChannel(messages chan Message)
func (*Controller) SetShutdownTimeout ¶
func (c *Controller) SetShutdownTimeout(d time.Duration)
func (*Controller) SetSignalsChannel ¶
func (c *Controller) SetSignalsChannel(signals chan os.Signal)
func (*Controller) SetState ¶
func (c *Controller) SetState(state State)
func (*Controller) SetWaitGroup ¶
func (c *Controller) SetWaitGroup(wg *sync.WaitGroup)
func (*Controller) Signals ¶
func (c *Controller) Signals() chan os.Signal
func (*Controller) Start ¶
func (c *Controller) Start()
Start launches all registered services. Duplicate calls while already running are no-ops.
func (*Controller) Status ¶ added in v1.6.0
func (c *Controller) Status() HealthReport
Status returns an aggregate health report for all registered services and health checks.
func (*Controller) Stop ¶
func (c *Controller) Stop()
Stop initiates a graceful shutdown. Duplicate calls while already stopping or stopped are safely ignored.
func (*Controller) Wait ¶
func (c *Controller) Wait()
func (*Controller) WaitGroup ¶
func (c *Controller) WaitGroup() *sync.WaitGroup
type ControllerOpt ¶
type ControllerOpt func(Configurable)
ControllerOpt is a functional option for configuring a Controller.
func WithLogger ¶
func WithLogger(l logger.Logger) ControllerOpt
WithLogger sets the controller logger.
func WithShutdownTimeout ¶
func WithShutdownTimeout(d time.Duration) ControllerOpt
WithShutdownTimeout sets the graceful shutdown timeout.
func WithoutSignals ¶
func WithoutSignals() ControllerOpt
WithoutSignals disables OS signal handling.
type HealthCheck ¶ added in v1.8.0
type HealthCheck struct {
// Name is the unique identifier for this check.
Name string
// Check is the function that performs the health check.
// It receives a context with the check's timeout applied.
Check func(ctx context.Context) CheckResult
// Timeout is the maximum duration for a single check execution.
// Default: 5s.
Timeout time.Duration
// Interval is the polling interval for async checks.
// Zero means synchronous (run on every health request).
Interval time.Duration
// Type determines which health endpoints this check feeds into.
// Default: CheckTypeReadiness.
Type CheckType
}
HealthCheck defines a named health check function.
type HealthCheckReporter ¶ added in v1.8.0
type HealthCheckReporter interface {
HealthReporter
// GetCheckResult returns the latest result for a named health check.
GetCheckResult(name string) (CheckResult, bool)
}
HealthCheckReporter extends HealthReporter with check-specific queries.
type HealthMessage ¶
type HealthMessage struct {
Host string `json:"host"`
Port int `json:"port"`
Status int `json:"status"`
Message string `json:"message"`
}
HealthMessage is the JSON response body for HTTP health endpoints.
type HealthReport ¶ added in v1.6.0
type HealthReport struct {
OverallHealthy bool `json:"overall_healthy"`
Services []ServiceStatus `json:"services"`
}
HealthReport is the aggregate health status across all registered services.
type HealthReporter ¶ added in v1.6.2
type HealthReporter interface {
Status() HealthReport
Liveness() HealthReport
Readiness() HealthReport
GetServiceInfo(name string) (ServiceInfo, bool)
}
HealthReporter provides read access to service health, liveness, and readiness reports, and to per-service runtime information. Handlers and transports that only need to query health should depend on this interface rather than the full Controllable.
type Message ¶
type Message string
Message represents a control message sent to the controller (e.g. "stop").
type ProbeFunc ¶ added in v1.6.0
type ProbeFunc func() error
ProbeFunc is a health check function for liveness or readiness probes.
type RestartPolicy ¶ added in v1.6.0
type RestartPolicy struct {
MaxRestarts int
InitialBackoff time.Duration
MaxBackoff time.Duration
HealthFailureThreshold int
HealthCheckInterval time.Duration
}
RestartPolicy defines how a service should be restarted on failure.
type Runner ¶
type Runner interface {
Start()
Stop()
IsRunning() bool
IsStopped() bool
IsStopping() bool
Register(id string, opts ...ServiceOption)
}
Runner provides service lifecycle operations.
type Service ¶
type Service struct {
Name string
Start StartFunc
Stop StopFunc
Status StatusFunc
Liveness ProbeFunc
Readiness ProbeFunc
RestartPolicy *RestartPolicy
}
Service represents a managed background service with start/stop lifecycle, health probes, and optional restart policy.
type ServiceInfo ¶ added in v1.6.0
type ServiceInfo struct {
Name string
RestartCount int
LastStarted time.Time
LastStopped time.Time
Error error
}
ServiceInfo holds runtime metadata about a registered service.
type ServiceOption ¶
type ServiceOption func(*Service)
ServiceOption is a functional option for configuring a Service.
func WithLiveness ¶ added in v1.6.0
func WithLiveness(fn ProbeFunc) ServiceOption
WithLiveness sets a liveness probe for the service.
Example ¶
package main
import (
"context"
"net/http"
"github.com/phpboyscout/go-tool-base/pkg/controls"
)
func main() {
controller := controls.NewController(context.Background(), controls.WithoutSignals())
controller.Register("api",
controls.WithStart(func(ctx context.Context) error { return nil }),
controls.WithLiveness(func() error {
// Check if the service can respond
resp, err := http.Get("http://localhost:8080/healthz")
if err != nil {
return err
}
_ = resp.Body.Close()
return nil
}),
)
_ = controller
}
Output:
func WithReadiness ¶ added in v1.6.0
func WithReadiness(fn ProbeFunc) ServiceOption
WithReadiness sets a readiness probe for the service.
func WithRestartPolicy ¶ added in v1.6.0
func WithRestartPolicy(policy RestartPolicy) ServiceOption
WithRestartPolicy configures automatic restart behaviour for a service.
Example ¶
package main
import (
"context"
"time"
"github.com/phpboyscout/go-tool-base/pkg/controls"
)
func main() {
controller := controls.NewController(context.Background(), controls.WithoutSignals())
controller.Register("worker",
controls.WithStart(func(ctx context.Context) error {
return nil
}),
controls.WithRestartPolicy(controls.RestartPolicy{
MaxRestarts: 3,
InitialBackoff: time.Second,
MaxBackoff: 30 * time.Second,
}),
)
_ = controller
}
Output:
func WithStart ¶
func WithStart(fn StartFunc) ServiceOption
WithStart sets the service's start function.
func WithStatus ¶
func WithStatus(fn StatusFunc) ServiceOption
WithStatus sets the service's health check function.
func WithStop ¶
func WithStop(fn StopFunc) ServiceOption
WithStop sets the service's graceful shutdown function.
type ServiceStatus ¶ added in v1.6.0
type ServiceStatus struct {
Name string `json:"name"`
Status string `json:"status"` // "OK", "ERROR"
Error string `json:"error,omitempty"`
}
ServiceStatus is the health status of a single service, used in HealthReport.
type Services ¶
type Services struct {
// contains filtered or unexported fields
}
Services manages the collection of registered services and their lifecycle.
type StartFunc ¶
StartFunc is the callback invoked to start a service. It receives a context that is cancelled when the controller shuts down.
type State ¶
type State string
State represents the lifecycle state of the controller (Created, Starting, Running, Stopped).
type StateAccessor ¶
type StateAccessor interface {
GetState() State
SetState(state State)
GetContext() context.Context
GetLogger() logger.Logger
}
StateAccessor provides read access to controller state and context.
type StatusFunc ¶
type StatusFunc func() error
StatusFunc is the callback invoked to check a service's health. Returns nil if healthy, an error otherwise.
type StopFunc ¶
StopFunc is the callback invoked to stop a service gracefully. The context carries the shutdown timeout.
type ValidErrorFunc ¶
ValidErrorFunc determines whether an error from a service is expected (e.g. http.ErrServerClosed) and should not trigger a restart.