Documentation
¶
Overview ¶
Package utils provides utility functions and types for the Lumen SDK.
The utils package contains common utilities used throughout the SDK:
- Structured error handling with LumenError
- Logging configuration and initialization
- Retry mechanisms with exponential backoff
- Circuit breaker for fault tolerance
- Health monitoring utilities
Structured Errors ¶
Use LumenError for consistent error handling:
if node == nil {
return utils.NodeNotFoundError(nodeID, map[string]interface{}{
"available_nodes": nodeCount,
})
}
Check error types programmatically:
if utils.HasErrorCode(err, utils.ErrCodeTimeout) {
// Handle timeout specifically
return retry(operation)
}
Logging ¶
Initialize structured logging:
logCfg := &config.LoggingConfig{
Level: "info",
Format: "json",
Output: "stdout",
}
utils.InitLogger(logCfg)
// Use the logger
utils.Logger.Info("Operation completed",
zap.String("operation", "inference"),
zap.Duration("duration", elapsed))
Retry Logic ¶
Add resilience with automatic retries:
retryConfig := utils.DefaultRetryConfig()
err := utils.Retry(ctx, retryConfig, func(ctx context.Context) error {
result, err := client.Infer(ctx, request)
if err != nil {
return err
}
return processResult(result)
})
The retry mechanism automatically determines if errors are retryable:
- Timeout errors: retried
- Network errors: retried
- Validation errors: not retried
- Authorization errors: not retried
Circuit Breaker ¶
Protect against cascading failures:
cb := utils.NewCircuitBreaker("ml-node-1", 5, 30*time.Second)
err := cb.Execute(func() error {
return client.Infer(ctx, request)
})
if err != nil {
if cb.GetState() == utils.CircuitOpen {
log.Println("Circuit breaker open, service unavailable")
}
}
Error Aggregation ¶
Collect multiple errors in batch operations:
aggr := utils.NewErrorAggregator()
for _, node := range nodes {
if err := node.Connect(); err != nil {
aggr.Add(err)
}
}
if aggr.HasErrors() {
log.Printf("Connection errors: %v", aggr.Error())
}
Role in Project ¶
The utils package provides foundational utilities that enhance the SDK's reliability, observability, and error handling. These utilities are used throughout the codebase to ensure consistent behavior and robust operation.
Index ¶
- Variables
- func Backoff(attempt int, base time.Duration, multiplier float64, max time.Duration) time.Duration
- func HasErrorCode(err error, code ErrorCode) bool
- func InitLogger(cfg *config.LoggingConfig)
- func IsLumenError(err error) bool
- func IsRetryable(err error) bool
- func NewRetryableError(err error, shouldRetry bool) error
- func Recover() error
- func Retry(ctx context.Context, config *RetryConfig, fn RetryFunc) error
- func RetryWithCallback(ctx context.Context, config *RetryConfig, fn RetryFunc, callback RetryCallback) error
- func SafeExecute(fn func() error) (err error)
- type CircuitBreaker
- type CircuitState
- type CompositeHealthChecker
- type ErrorAggregator
- type ErrorCode
- type GRPCHealthChecker
- type HTTPHealthChecker
- type HealthCheckResult
- type HealthChecker
- type HealthMonitor
- func (hm *HealthMonitor) AddChecker(checker HealthChecker)
- func (hm *HealthMonitor) CheckAll(ctx context.Context) map[string]*HealthCheckResult
- func (hm *HealthMonitor) GetAllResults() map[string]*HealthCheckResult
- func (hm *HealthMonitor) GetHealthyCheckers() []string
- func (hm *HealthMonitor) GetResult(name string) (*HealthCheckResult, bool)
- func (hm *HealthMonitor) GetUnhealthyCheckers() []string
- func (hm *HealthMonitor) IsRunning() bool
- func (hm *HealthMonitor) RemoveChecker(name string)
- func (hm *HealthMonitor) Start(ctx context.Context)
- func (hm *HealthMonitor) Stop()
- type HealthStatus
- type LumenError
- func CodecMismatchError(expected, actual string, details ...interface{}) *LumenError
- func ConnectionFailedError(target string, details ...interface{}) *LumenError
- func DiscoveryFailedError(message string, details ...interface{}) *LumenError
- func ForbiddenError(message string, details ...interface{}) *LumenError
- func GetLumenError(err error) (*LumenError, bool)
- func InternalError(message string, details ...interface{}) *LumenError
- func InvalidError(message string, details ...interface{}) *LumenError
- func NewLumenError(code ErrorCode, message string, details ...interface{}) *LumenError
- func NodeNotFoundError(nodeID string, details ...interface{}) *LumenError
- func NotFoundError(message string, details ...interface{}) *LumenError
- func RequestFailedError(message string, details ...interface{}) *LumenError
- func ResponseFailedError(message string, details ...interface{}) *LumenError
- func ServiceUnavailableError(service string, details ...interface{}) *LumenError
- func TaskUnsupportedError(task string, details ...interface{}) *LumenError
- func TimeoutError(message string, details ...interface{}) *LumenError
- func UnauthorizedError(message string, details ...interface{}) *LumenError
- func UnavailableError(message string, details ...interface{}) *LumenError
- func Wrap(err error, code ErrorCode, message string, details ...interface{}) *LumenError
- type RetryCallback
- type RetryConfig
- type RetryFunc
- type RetryableError
Constants ¶
This section is empty.
Variables ¶
var Logger *zap.Logger
Logger is the global structured logger instance for the Lumen SDK.
This is a zap.Logger configured based on the logging configuration. Use this for performance-critical logging with structured fields.
var Sugar *zap.SugaredLogger
Sugar is the global sugared logger for more convenient logging.
SugaredLogger provides a more ergonomic API with printf-style formatting at the cost of minor performance overhead. Use for non-critical paths.
Functions ¶
func InitLogger ¶
func InitLogger(cfg *config.LoggingConfig)
InitLogger initializes the global logger with the specified configuration.
This function sets up structured logging with configurable:
- Log level (debug, info, warn, error, fatal)
- Output format (json, text/console)
- Output destination (stdout, stderr, file)
- File rotation (when using file output)
The function initializes both Logger (structured) and Sugar (convenient) loggers. It should be called once during application startup.
Parameters:
- cfg: Logging configuration specifying level, format, and output
Role in project: Configures the centralized logging system used throughout the SDK. Proper logging is essential for debugging, monitoring, and operational visibility.
Example:
// Initialize with custom config
logCfg := &config.LoggingConfig{
Level: "debug",
Format: "json",
Output: "stdout",
}
utils.InitLogger(logCfg)
// Use the logger
utils.Logger.Info("Client started",
zap.String("version", "1.0.0"),
zap.Int("nodes", 3))
// Or use sugar for convenience
utils.Sugar.Infof("Client started: version=%s, nodes=%d", "1.0.0", 3)
func NewRetryableError ¶
NewRetryableError wraps an error with retry eligibility information.
Use this to explicitly mark errors as retryable or non-retryable when the automatic detection isn't sufficient for your use case.
Parameters:
- err: The underlying error
- shouldRetry: Whether this error should trigger a retry
Returns:
- error: Wrapped error implementing RetryableError interface
Example:
if networkErr != nil {
// Mark as retryable
return utils.NewRetryableError(networkErr, true)
}
if validationErr != nil {
// Mark as non-retryable
return utils.NewRetryableError(validationErr, false)
}
func Retry ¶
func Retry(ctx context.Context, config *RetryConfig, fn RetryFunc) error
Retry executes a function with automatic retry on transient failures.
This function implements exponential backoff retry logic with configurable parameters. It automatically determines if errors are retryable based on:
- RetryableError interface implementation
- Lumen error codes (timeout, unavailable, connection failed)
- Common network error patterns
Non-retryable errors (validation, authorization, etc.) fail immediately without retry.
Parameters:
- ctx: Context for cancellation (respects context timeout/cancellation)
- config: Retry configuration (attempts, backoff, etc.)
- fn: The function to execute with retry logic
Returns:
- error: The last error encountered, or nil if successful
Role in project: Adds resilience to ML inference operations by handling transient network and service failures automatically. Essential for production reliability.
Example:
retryConfig := utils.DefaultRetryConfig()
err := utils.Retry(ctx, retryConfig, func(ctx context.Context) error {
result, err := client.Infer(ctx, request)
if err != nil {
return err
}
// Process result
return nil
})
if err != nil {
log.Printf("Failed after retries: %v", err)
}
func RetryWithCallback ¶
func RetryWithCallback(ctx context.Context, config *RetryConfig, fn RetryFunc, callback RetryCallback) error
Types ¶
type CircuitBreaker ¶
type CircuitBreaker struct {
// contains filtered or unexported fields
}
CircuitBreaker implements the circuit breaker pattern for fault tolerance.
The circuit breaker prevents cascading failures by:
- Tracking consecutive failures
- Opening the circuit after threshold failures (rejecting requests immediately)
- Allowing test requests after a reset timeout (half-open state)
- Closing the circuit when requests succeed again
States:
- Closed: Normal operation, all requests go through
- Open: Circuit tripped, requests fail fast without execution
- Half-Open: Testing if service recovered, limited requests allowed
Role in project: Protects the system from repeatedly calling failing services, allowing them time to recover and preventing resource exhaustion.
Example:
cb := utils.NewCircuitBreaker("ml-node-1", 5, 30*time.Second)
err := cb.Execute(func() error {
return client.Infer(ctx, request)
})
if err != nil {
if cb.GetState() == utils.CircuitOpen {
log.Println("Circuit breaker open, service unavailable")
}
}
func NewCircuitBreaker ¶
func NewCircuitBreaker(name string, maxFailures int, resetTime time.Duration) *CircuitBreaker
NewCircuitBreaker 创建断路器
func (*CircuitBreaker) Execute ¶
func (cb *CircuitBreaker) Execute(fn func() error) error
Execute 执行函数
func (*CircuitBreaker) GetState ¶
func (cb *CircuitBreaker) GetState() CircuitState
GetState 获取断路器状态
type CircuitState ¶
type CircuitState int
const ( CircuitClosed CircuitState = iota CircuitOpen CircuitHalfOpen )
type CompositeHealthChecker ¶
type CompositeHealthChecker struct {
// contains filtered or unexported fields
}
CompositeHealthChecker 复合健康检查器
func NewCompositeHealthChecker ¶
func NewCompositeHealthChecker(name string, checkers ...HealthChecker) *CompositeHealthChecker
NewCompositeHealthChecker 创建复合健康检查器
func (*CompositeHealthChecker) Check ¶
func (h *CompositeHealthChecker) Check(ctx context.Context) *HealthCheckResult
Check 执行复合健康检查
type ErrorAggregator ¶
type ErrorAggregator struct {
// contains filtered or unexported fields
}
ErrorAggregator collects multiple errors for batch operations.
Use this when performing operations on multiple items where you want to:
- Continue processing despite individual failures
- Report all errors at once rather than failing on first error
- Track partial success/failure in batch operations
Role in project: Enables robust error handling in batch operations like initializing multiple connections or processing multiple inference requests.
Example:
aggr := utils.NewErrorAggregator()
for _, node := range nodes {
if err := node.Connect(); err != nil {
aggr.Add(err)
}
}
if aggr.HasErrors() {
log.Printf("Connection errors: %v", aggr.Error())
}
type ErrorCode ¶
type ErrorCode string
ErrorCode represents a standardized error code for the Lumen SDK.
Error codes provide a machine-readable way to identify error types, enabling clients to handle errors programmatically with appropriate retry logic, user messages, and recovery strategies.
Role in project: Standardizes error handling across the SDK, enabling consistent error reporting and intelligent error recovery.
const ( // General error codes applicable across all components ErrCodeInternal ErrorCode = "INTERNAL" // Internal server/SDK error ErrCodeInvalid ErrorCode = "INVALID" ErrCodeTimeout ErrorCode = "TIMEOUT" ErrCodeNotFound ErrorCode = "NOT_FOUND" ErrCodeForbidden ErrorCode = "FORBIDDEN" // Lumen特定错误码 ErrCodeNodeNotFound ErrorCode = "NODE_NOT_FOUND" ErrCodeTaskUnsupported ErrorCode = "TASK_UNSUPPORTED" ErrCodecMismatch ErrorCode = "CODEC_MISMATCH" ErrCodeDiscoveryFailed ErrorCode = "DISCOVERY_FAILED" ErrCodeConnectionFailed ErrorCode = "CONNECTION_FAILED" ErrCodeRequestFailed ErrorCode = "REQUEST_FAILED" ErrCodeResponseFailed ErrorCode = "RESPONSE_FAILED" )
type GRPCHealthChecker ¶
type GRPCHealthChecker struct {
// contains filtered or unexported fields
}
GRPCHealthChecker gRPC健康检查器
func NewGRPCHealthChecker ¶
func NewGRPCHealthChecker(client pb.InferenceClient, name string, timeout time.Duration) *GRPCHealthChecker
NewGRPCHealthChecker 创建gRPC健康检查器
func (*GRPCHealthChecker) Check ¶
func (h *GRPCHealthChecker) Check(ctx context.Context) *HealthCheckResult
Check 执行健康检查
type HTTPHealthChecker ¶
type HTTPHealthChecker struct {
// contains filtered or unexported fields
}
HTTPHealthChecker HTTP健康检查器
func NewHTTPHealthChecker ¶
func NewHTTPHealthChecker(url, name string, timeout time.Duration) *HTTPHealthChecker
NewHTTPHealthChecker 创建HTTP健康检查器
func (*HTTPHealthChecker) Check ¶
func (h *HTTPHealthChecker) Check(ctx context.Context) *HealthCheckResult
Check 执行健康检查
type HealthCheckResult ¶
type HealthCheckResult struct {
Status HealthStatus `json:"status"`
Message string `json:"message"`
Timestamp time.Time `json:"timestamp"`
Details map[string]interface{} `json:"details,omitempty"`
Duration time.Duration `json:"duration"`
}
HealthCheckResult 健康检查结果
type HealthChecker ¶
type HealthChecker interface {
Check(ctx context.Context) *HealthCheckResult
Name() string
}
HealthChecker 健康检查器接口
type HealthMonitor ¶
type HealthMonitor struct {
// contains filtered or unexported fields
}
HealthMonitor 健康监控器
func NewHealthMonitor ¶
func NewHealthMonitor(interval time.Duration) *HealthMonitor
NewHealthMonitor 创建健康监控器
func (*HealthMonitor) AddChecker ¶
func (hm *HealthMonitor) AddChecker(checker HealthChecker)
AddChecker 添加健康检查器
func (*HealthMonitor) CheckAll ¶
func (hm *HealthMonitor) CheckAll(ctx context.Context) map[string]*HealthCheckResult
CheckAll 执行所有健康检查
func (*HealthMonitor) GetAllResults ¶
func (hm *HealthMonitor) GetAllResults() map[string]*HealthCheckResult
GetAllResults 获取所有检查器的最新结果
func (*HealthMonitor) GetHealthyCheckers ¶
func (hm *HealthMonitor) GetHealthyCheckers() []string
GetHealthyCheckers 获取所有健康的检查器
func (*HealthMonitor) GetResult ¶
func (hm *HealthMonitor) GetResult(name string) (*HealthCheckResult, bool)
GetResult 获取特定检查器的最新结果
func (*HealthMonitor) GetUnhealthyCheckers ¶
func (hm *HealthMonitor) GetUnhealthyCheckers() []string
GetUnhealthyCheckers 获取所有不健康的检查器
func (*HealthMonitor) RemoveChecker ¶
func (hm *HealthMonitor) RemoveChecker(name string)
RemoveChecker 移除健康检查器
type HealthStatus ¶
type HealthStatus string
HealthStatus 健康状态
const ( StatusHealthy HealthStatus = "healthy" StatusUnhealthy HealthStatus = "unhealthy" StatusUnknown HealthStatus = "unknown" )
type LumenError ¶
type LumenError struct {
Code ErrorCode `json:"code"`
Message string `json:"message"`
Details interface{} `json:"details,omitempty"`
Cause error `json:"-"`
}
LumenError represents a structured error from the Lumen SDK.
This error type provides:
- Standardized error codes for programmatic handling
- Human-readable error messages
- Optional structured details (can be logged or returned to API clients)
- Error wrapping/chaining support via Cause
Role in project: Provides structured, actionable error information throughout the SDK. Essential for debugging, monitoring, and building resilient applications.
Example:
err := utils.NodeNotFoundError("node-123", map[string]interface{}{
"requested_at": time.Now(),
"available_nodes": 5,
})
if utils.HasErrorCode(err, utils.ErrCodeNodeNotFound) {
// Handle node not found specifically
}
func CodecMismatchError ¶
func CodecMismatchError(expected, actual string, details ...interface{}) *LumenError
func ConnectionFailedError ¶
func ConnectionFailedError(target string, details ...interface{}) *LumenError
func DiscoveryFailedError ¶
func DiscoveryFailedError(message string, details ...interface{}) *LumenError
func ForbiddenError ¶
func ForbiddenError(message string, details ...interface{}) *LumenError
func InternalError ¶
func InternalError(message string, details ...interface{}) *LumenError
InternalError creates an internal error indicating an unexpected condition.
Use for unexpected errors, programming errors, or unhandled edge cases. These typically indicate bugs or misconfigurations.
Example:
if node == nil {
return utils.InternalError("node should never be nil at this point")
}
func InvalidError ¶
func InvalidError(message string, details ...interface{}) *LumenError
func NewLumenError ¶
func NewLumenError(code ErrorCode, message string, details ...interface{}) *LumenError
NewLumenError creates a new LumenError with the specified code and message.
Parameters:
- code: Standardized error code (e.g., ErrCodeTimeout)
- message: Human-readable error description
- details: Optional structured details (first element used if provided)
Returns:
- *LumenError: New error instance
Example:
err := utils.NewLumenError(
utils.ErrCodeTimeout,
"inference request timed out",
map[string]interface{}{"timeout": "30s", "node": "node-1"},
)
func NodeNotFoundError ¶
func NodeNotFoundError(nodeID string, details ...interface{}) *LumenError
NodeNotFoundError creates an error indicating a requested ML node was not found.
This error typically occurs when:
- The node ID doesn't exist in the discovered nodes
- The node has been removed or gone offline
- Service discovery hasn't found any nodes yet
Parameters:
- nodeID: The ID of the node that was not found
- details: Optional additional context
Example:
node, exists := discovery.GetNode(nodeID)
if !exists {
return utils.NodeNotFoundError(nodeID, map[string]interface{}{
"available_nodes": discovery.GetNodeCount(),
})
}
func NotFoundError ¶
func NotFoundError(message string, details ...interface{}) *LumenError
func RequestFailedError ¶
func RequestFailedError(message string, details ...interface{}) *LumenError
func ResponseFailedError ¶
func ResponseFailedError(message string, details ...interface{}) *LumenError
func ServiceUnavailableError ¶
func ServiceUnavailableError(service string, details ...interface{}) *LumenError
func TaskUnsupportedError ¶
func TaskUnsupportedError(task string, details ...interface{}) *LumenError
func TimeoutError ¶
func TimeoutError(message string, details ...interface{}) *LumenError
func UnauthorizedError ¶
func UnauthorizedError(message string, details ...interface{}) *LumenError
func UnavailableError ¶
func UnavailableError(message string, details ...interface{}) *LumenError
func Wrap ¶
func Wrap(err error, code ErrorCode, message string, details ...interface{}) *LumenError
Wrap wraps an existing error with additional context and a Lumen error code.
This function creates a new LumenError that preserves the original error as the cause, enabling error chain unwrapping with errors.Unwrap().
Parameters:
- err: The original error to wrap
- code: Lumen error code for categorization
- message: Additional context message
- details: Optional structured details
Returns:
- *LumenError: Wrapped error with Lumen context
Example:
_, err := conn.Dial(address)
if err != nil {
return utils.Wrap(err, utils.ErrCodeConnectionFailed,
"failed to connect to ML node",
map[string]string{"address": address})
}
type RetryConfig ¶
type RetryConfig struct {
Enabled bool `json:"enabled"`
MaxAttempts int `json:"max_attempts"`
Backoff time.Duration `json:"backoff"`
MaxBackoff time.Duration `json:"max_backoff"`
Multiplier float64 `json:"multiplier"`
}
RetryConfig defines configuration for retry behavior with exponential backoff.
Retry mechanisms help handle transient failures in distributed systems like network timeouts, temporary service unavailability, and connection issues.
Role in project: Provides resilience against temporary failures in ML inference requests, making the SDK more robust in production environments.
Example:
retryConfig := &utils.RetryConfig{
Enabled: true,
MaxAttempts: 3,
Backoff: 100 * time.Millisecond,
MaxBackoff: 5 * time.Second,
Multiplier: 2.0,
}
type RetryFunc ¶
RetryFunc is the function signature for operations that can be retried.
Functions of this type should be idempotent or handle their own state to ensure correct behavior when executed multiple times.
type RetryableError ¶
type RetryableError interface {
ShouldRetry() bool
}
RetryableError is an interface for errors that indicate whether they should be retried.
Implement this interface on custom error types to control retry behavior. The SDK automatically determines retry eligibility for common error types.
Role in project: Enables intelligent retry decisions based on error semantics, preventing unnecessary retries for non-transient errors (e.g., validation errors).