This document provides detailed documentation for all exported types in the CPRA monitoring system.
Configuration struct for the Controller.
Fields:
- Debug (bool) - Enable debug-level logging
- PipelineConfig (loader.PipelineConfig) - Configuration for the loader
- QueueCapacity (uint64) - Initial queue capacity (must be power of 2)
- WorkerConfig (queue.WorkerPoolConfig) - Worker pool configuration
- BatchSize (int) - Batch size for system processing
- UpdateInterval (time.Duration) - Update interval (deprecated, ark-tools TPS=100 controls timing)
- SizingServiceTime (time.Duration) - τ (tau) - expected service time per job
- SizingSLO (time.Duration) - W target - end-to-end latency SLO
- SizingHeadroomPct (float64) - Safe headroom as fraction (e.g., 0.15 = 15%)
Methods:
- None (data struct)
When to use:
- When creating a new Controller instance
- When customizing system behavior before initialization
Example:
config := controller.DefaultConfig()
config.Debug = true
config.QueueCapacity = 131072
config.BatchSize = 2000
config.SizingServiceTime = 20 * time.Millisecond
config.SizingSLO = 200 * time.Millisecond
config.SizingHeadroomPct = 0.15
ctrl := controller.NewController(config)Manages the ECS world and its systems using ark-tools.
Fields:
- All fields are unexported (internal state)
Methods:
- LoadMonitors(ctx context.Context, filename string) error
- Start() error
- Stop()
- GetWorld() *ecs.World
- PrintShutdownMetrics()
Used by:
- Main application entry point
- Integration tests
Example:
config := controller.DefaultConfig()
ctrl := controller.NewController(config)
defer ctrl.Stop()
ctx := context.Background()
if err := ctrl.LoadMonitors(ctx, "monitors.yaml"); err != nil {
log.Fatal(err)
}
if err := ctrl.Start(); err != nil {
log.Fatal(err)
}Structured logger for component-specific logging with multiple log levels.
Fields:
- All fields are unexported
Methods:
- Debug(format string, args ...interface{})
- Info(format string, args ...interface{})
- Warn(format string, args ...interface{})
- Error(format string, args ...interface{})
- LogSystemPerformance(name string, duration time.Duration, count int)
When to use:
- When creating component-specific loggers
- For structured logging with different severity levels
Example:
logger := controller.NewLogger("MyComponent", true)
logger.Info("Component started")
logger.Debug("Processing item %d", itemID)
logger.Error("Failed to process: %v", err)Adapts the controller loggers to the systems interface.
Fields:
- logger (interface) - Logger implementation
Methods:
- Info(format string, args ...interface{})
- Debug(format string, args ...interface{})
- Warn(format string, args ...interface{})
- Error(format string, args ...interface{})
- LogSystemPerformance(name string, duration time.Duration, count int)
- LogComponentState(entityID uint32, component string, action string)
When to use:
- Internal adapter - typically not used directly by applications
Aggregates system performance metrics.
Fields:
- All fields are unexported
Methods:
- RecordSystemMetric(name string, count int, duration time.Duration)
- GetAggregateMetrics() AggregateMetrics
When to use:
- When collecting and aggregating system performance data
- For performance monitoring and analysis
Example:
metrics := controller.NewMetricsAggregator()
metrics.RecordSystemMetric("pulse", 100, 50*time.Millisecond)
aggregate := metrics.GetAggregateMetrics()
fmt.Printf("Total operations: %d\n", aggregate.TotalOperations)Monitors and controls application memory usage.
Fields:
- All fields are unexported
Methods:
- Start()
- Stop()
- GetMemoryStats() (alloc, totalAlloc, sys uint64)
When to use:
- When managing application memory limits
- For automatic GC triggering based on memory thresholds
Example:
memMgr := controller.NewMemoryManager(8, 30) // 8GB max, 30s GC interval
memMgr.Start()
defer memMgr.Stop()Tracks errors and provides circuit breaker functionality.
Fields:
- All fields are unexported
Methods:
- RecordError()
- ShouldRecover() bool
- Reset()
When to use:
- When implementing error tracking and recovery logic
- For circuit breaker patterns
Example:
recovery := controller.NewRecoverySystem(10, 1*time.Minute)
if err := doOperation(); err != nil {
recovery.RecordError()
if recovery.ShouldRecover() {
// Trigger recovery logic
}
}Distributed tracer for component tracing.
Fields:
- All fields are unexported
Methods:
- StartSpan(operation string) *TraceSpan
- GetSpan(spanID string) (*TraceSpan, bool)
When to use:
- When implementing distributed tracing
- For performance analysis and debugging
Example:
tracer := controller.NewTracer("PulseSystem", true)
span := tracer.StartSpan("ProcessPulse")
defer span.End()
// ... do work ...Represents a single trace span.
Fields:
- SpanID (string) - Unique span identifier
- Operation (string) - Operation name
- StartTime (time.Time) - Span start time
- EndTime (time.Time) - Span end time (zero if not ended)
- Duration (time.Duration) - Span duration
- Component (string) - Component name
Methods:
- End()
- AddMetadata(key string, value interface{})
When to use:
- Automatically created by Tracer.StartSpan()
- For tracking operation timing
The queue package provides multiple queue implementations and a dynamic worker pool system. For detailed architecture explanation, see the Architecture Overview document.
Defines the interface for a generic, thread-safe queue system.
Methods:
- Enqueue(job jobs.Job) error
- EnqueueBatch(jobs []interface{}) error
- Dequeue() (jobs.Job, error)
- DequeueBatch(maxSize int) ([]jobs.Job, error)
- Close()
- Stats() Stats
Implementations:
- AdaptiveQueue
- WorkivaQueue
- HybridQueue
- BoundedQueue
When to use:
- When you need a decoupled queue interface
- For dependency injection and testing
Example:
var q queue.Queue
config := queue.DefaultQueueConfig()
q, err := queue.NewQueue(config)
if err != nil {
log.Fatal(err)
}
defer q.Close()
err = q.Enqueue(myJob)
stats := q.Stats()
fmt.Printf("Queue depth: %d\n", stats.QueueDepth)Performance metrics for a queue.
Fields:
- LastEnqueue (time.Time) - Time of last enqueue operation
- LastDequeue (time.Time) - Time of last dequeue operation
- AvgQueueTime (time.Duration) - Average time jobs spend in queue
- MaxQueueTime (time.Duration) - Maximum time a job spent in queue
- Dequeued (int64) - Total jobs dequeued
- Dropped (int64) - Total jobs dropped
- QueueDepth (int) - Current number of jobs in queue
- MaxJobLatency (time.Duration) - Maximum job latency observed
- AvgJobLatency (time.Duration) - Average job latency
- EnqueueRate (float64) - Enqueue rate (jobs/sec)
- DequeueRate (float64) - Dequeue rate (jobs/sec)
- Enqueued (int64) - Total jobs enqueued
- Capacity (int) - Queue capacity
- SampleWindow (time.Duration) - Time window for rate calculations
Methods:
- None (data struct)
When to use:
- When monitoring queue performance
- For capacity planning and sizing decisions
Example:
stats := myQueue.Stats()
fmt.Printf("Enqueue rate: %.2f jobs/sec\n", stats.EnqueueRate)
fmt.Printf("Queue depth: %d/%d (%.1f%% full)\n",
stats.QueueDepth, stats.Capacity,
100.0*float64(stats.QueueDepth)/float64(stats.Capacity))
fmt.Printf("Avg queue time: %v\n", stats.AvgQueueTime)Configuration for queue creation.
Fields:
- Name (string) - Queue name for logging
- Type (QueueType) - Type of queue to create
- Capacity (int) - Queue capacity
- HybridConfig (HybridQueueConfig) - Configuration for hybrid queues
Methods:
- None (data struct)
When to use:
- When creating queues with specific configuration
- For customizing queue behavior
Example:
config := queue.QueueConfig{
Name: "pulse",
Type: queue.QueueTypeHybrid,
Capacity: 65536,
HybridConfig: queue.HybridQueueConfig{
RingCapacity: 65536,
OverflowCapacity: 100000,
DropPolicy: queue.DropPolicyDropNewest,
},
}
q, err := queue.NewQueue(config)Represents the type of queue to create.
Constants:
- QueueTypeAdaptive ("adaptive") - Adaptive queue that adjusts behavior
- QueueTypeWorkiva ("workiva") - Workiva ring buffer queue
- QueueTypeHybrid ("hybrid") - Hybrid ring buffer + heap queue
When to use:
- When specifying queue type in QueueConfig
Manages a pool of workers that execute jobs from a queue with dynamic scaling.
Fields:
- All fields are unexported
Methods:
- Start()
- DrainAndStop()
- GetRouter() *ResultRouter
- Stats() WorkerPoolStats
- Pause() - Note: No-op in v0.5
- Resume() - Note: No-op in v0.5
When to use:
- When you need concurrent job processing with auto-scaling
- For processing jobs from queues with result routing
Example:
config := queue.DefaultWorkerPoolConfig()
config.MinWorkers = 5
config.MaxWorkers = 100
pool, err := queue.NewDynamicWorkerPool(myQueue, config, logger)
if err != nil {
log.Fatal(err)
}
pool.Start()
defer pool.DrainAndStop()
router := pool.GetRouter()
go func() {
for results := range router.PulseResultChan {
processResults(results)
}
}()Configuration for the DynamicWorkerPool.
Fields:
- MinWorkers (int) - Minimum number of workers
- MaxWorkers (int) - Maximum number of workers
- AdjustmentInterval (time.Duration) - How often to adjust worker count
- ResultBatchSize (int) - Batch size for result processing
- ResultBatchTimeout (time.Duration) - Timeout for partial batches
- ResultChannelDepth (int) - Buffer size for result channels
- TargetQueueLatency (time.Duration) - Target queue latency for scaling
- PreAlloc (bool) - Pre-allocate worker goroutines
- NonBlocking (bool) - Use non-blocking mode
- MaxBlockingTasks (int) - Max tasks to block on (0 = unlimited)
- ExpiryDuration (time.Duration) - Worker expiry duration
Methods:
- None (data struct)
When to use:
- When creating DynamicWorkerPool instances
- For customizing worker pool behavior
Example:
config := queue.WorkerPoolConfig{
MinWorkers: 10,
MaxWorkers: 1000,
AdjustmentInterval: 5 * time.Second,
ResultBatchSize: 512,
ResultBatchTimeout: 10 * time.Millisecond,
ResultChannelDepth: 2048,
TargetQueueLatency: 100 * time.Millisecond,
PreAlloc: false,
NonBlocking: false,
ExpiryDuration: 5 * time.Minute,
}
pool, _ := queue.NewDynamicWorkerPool(myQueue, config, logger)Runtime metrics for the dynamic worker pool.
Fields:
- LastScaleTime (time.Time) - Time of last scaling event
- MinWorkers (int) - Minimum worker limit
- MaxWorkers (int) - Maximum worker limit
- CurrentCapacity (int) - Current worker capacity
- RunningWorkers (int) - Currently running workers
- WaitingTasks (int) - Tasks waiting for workers
- TargetWorkers (int) - Target worker count
- TasksSubmitted (int64) - Total tasks submitted
- TasksCompleted (int64) - Total tasks completed
- ScalingEvents (int64) - Number of scaling events
- PendingResults (int) - Results waiting to be processed
Methods:
- None (data struct)
When to use:
- When monitoring worker pool performance
- For debugging worker pool behavior
Example:
stats := pool.Stats()
utilization := 100.0 * float64(stats.RunningWorkers) / float64(stats.CurrentCapacity)
fmt.Printf("Workers: %d/%d (%.1f%% utilized)\n",
stats.RunningWorkers, stats.CurrentCapacity, utilization)
fmt.Printf("Tasks: %d submitted, %d completed\n",
stats.TasksSubmitted, stats.TasksCompleted)Routes job results to type-specific channels.
Fields:
- PulseResultChan (chan []jobs.Result) - Channel for pulse results
- InterventionResultChan (chan []jobs.Result) - Channel for intervention results
- CodeResultChan (chan []jobs.Result) - Channel for code results
Methods:
- RouteResults(results []jobs.Result)
- Close()
When to use:
- Automatically used by DynamicWorkerPool
- For accessing type-specific result channels
Example:
router := pool.GetRouter()
go func() {
for results := range router.PulseResultChan {
for _, result := range results {
processPulseResult(result)
}
}
}()
go func() {
for results := range router.InterventionResultChan {
for _, result := range results {
processInterventionResult(result)
}
}
}()Adaptive queue that adjusts its behavior based on load.
Fields:
- All fields are unexported
Methods:
- Implements Queue interface
When to use:
- For very large entity counts (>500K monitors)
- When load patterns are unpredictable
Example:
q, err := queue.NewAdaptiveQueue(65536)
if err != nil {
log.Fatal(err)
}Combines ring buffer and heap with configurable drop policy.
Fields:
- All fields are unexported
Methods:
- Implements Queue interface
When to use:
- Default queue choice for most workloads
- When you need configurable drop policies
Example:
config := queue.DefaultHybridQueueConfig()
config.DropPolicy = queue.DropPolicyDropNewest
config.RingCapacity = 32768
config.OverflowCapacity = 100000
q, err := queue.NewHybridQueue(config)Configuration for HybridQueue.
Fields:
- Name (string) - Queue name for logging
- RingCapacity (int) - Ring buffer capacity (must be power of 2)
- OverflowCapacity (int) - Overflow slice capacity
- DropPolicy (DropPolicy) - Policy when both ring and overflow are full
Methods:
- None (data struct)
When to use:
- When creating HybridQueue instances
Example:
config := queue.HybridQueueConfig{
Name: "myqueue",
RingCapacity: 65536,
OverflowCapacity: 100000,
DropPolicy: queue.DropPolicyDropOldest,
}Policy for dropping items when queue is full.
Constants:
- DropPolicyReject - Reject new items (return error)
- DropPolicyDropOldest - Drop oldest items
- DropPolicyDropNewest - Drop newest items
When to use:
- When configuring HybridQueue behavior
Fixed-capacity queue with blocking behavior.
Fields:
- All fields are unexported
Methods:
- Implements Queue interface
When to use:
- When you need strict capacity limits
- For testing or simple scenarios
Zero-size tag component marking an entity as disabled.
Fields:
- None (zero-size struct)
Methods:
- None
When to use:
- Added to entities that should be excluded from processing
- Using a tag allows filters to exclude disabled entities efficiently at the archetype level
Example:
// Add Disabled component to an entity
world.Add(entity, ecs.C[components.Disabled]())
// Filter excludes disabled entities
filter := ecs.NewFilter2[components.MonitorState, components.PulseConfig](world).
Without(ecs.C[components.Disabled]())Consolidates all monitor state into a single component.
Fields:
- LastPulseCheckTime (time.Time) - Time the last pulse dispatch was enqueued (scheduling source of truth)
- LastEventTime (time.Time) - Time of the last processed pipeline event
- LastSuccessTime (time.Time) - Time of last successful check
- NextCheckTime (time.Time) - Scheduled time for next check
- LastError (error) - Last error encountered
- Name (string) - Monitor name
- PendingColor (ColorCode) - Pending alert color (uses ColorCode enum, not string)
- ConsecutiveFailures (int) - Number of consecutive failures
- PulseFailures (int) - Total pulse failures
- InterventionFailures (int) - Total intervention failures
- RecoveryStreak (int) - Current recovery streak
- VerifyRemaining (int) - Remaining verification checks
- Flags (uint32) - Bitfield for state flags
State Flag Constants:
- StatePulseNeeded (1 << 1)
- StatePulsePending (1 << 2)
- StatePulseFirstCheck (1 << 3)
- StateInterventionNeeded (1 << 5)
- StateInterventionPending (1 << 6)
- StateCodeNeeded (1 << 7)
- StateCodePending (1 << 8)
- StateIncidentOpen (1 << 9)
- StateVerifying (1 << 10)
Methods:
- IsPulseNeeded() bool
- IsPulsePending() bool
- IsPulseFirstCheck() bool
- IsInterventionNeeded() bool
- IsInterventionPending() bool
- IsCodeNeeded() bool
- IsCodePending() bool
- SetPulseNeeded(needed bool)
- SetPulsePending(pending bool)
- SetPulseFirstCheck(firstCheck bool)
- SetInterventionNeeded(needed bool)
- SetInterventionPending(pending bool)
- SetCodeNeeded(needed bool)
- SetCodePending(pending bool)
When to use:
- Required component for all monitor entities
- Tracks complete monitor state in a single component
Example:
state := &components.MonitorState{
Name: "web-server-01",
NextCheckTime: time.Now().Add(60 * time.Second),
}
state.SetPulseNeeded(true)
world.Add(entity, ecs.C[components.MonitorState](), state)Consolidates pulse configuration.
Fields:
- Config (schema.PulseConfig) - Type-specific pulse configuration
- Type (string) - Pulse type (http, tcp, icmp, etc.)
- Timeout (time.Duration) - Check timeout
- Interval (time.Duration) - Check interval
- Retries (int) - Number of retries on failure
- UnhealthyThreshold (int) - Failures before marking unhealthy
- HealthyThreshold (int) - Successes before marking healthy
Methods:
- Copy() *PulseConfig - Creates a deep copy
When to use:
- Attached to entities that require health checking
- Defines how and when pulse checks are performed
Example:
pulseCfg := &components.PulseConfig{
Type: "http",
Interval: 60 * time.Second,
Timeout: 5 * time.Second,
Retries: 3,
UnhealthyThreshold: 3,
HealthyThreshold: 2,
}
world.Add(entity, ecs.C[components.PulseConfig](), pulseCfg)Consolidates intervention configuration.
Fields:
- Target (schema.InterventionTarget) - Intervention target configuration
- Action (string) - Action to perform (restart, reboot, etc.)
- MaxFailures (int) - Maximum failures before giving up
Methods:
- Copy() *InterventionConfig - Creates a deep copy
When to use:
- Attached to entities that support automated remediation
- Defines remediation actions
Example:
intCfg := &components.InterventionConfig{
Action: "restart",
MaxFailures: 3,
}
world.Add(entity, ecs.C[components.InterventionConfig](), intCfg)Consolidates all code configurations using a fixed array for memory efficiency.
Fields:
- Configs ([MaxColors]ConfigID) - Fixed array of config IDs by color index
Methods:
- Copy() *CodeConfig - Creates a deep copy
When to use:
- Attached to entities that require alerting
- Supports multiple code colors per monitor (up to MaxColors = 8)
Note: Configurations are stored in a shared registry and referenced by ConfigID. Use the registry to resolve actual ColorCodeConfig values.
Configuration for a specific code color.
Fields:
- Config (schema.CodeNotification) - Notification configuration
- Notify (string) - Notification target
- MaxFailures (int) - Max failures before escalation
- Dispatch (bool) - Whether to dispatch immediately
Methods:
- Copy() *ColorCodeConfig - Creates a deep copy
When to use:
- Used within CodeConfig map
Consolidates all code status using a fixed array for memory efficiency.
Fields:
- Status ([MaxColors]ColorCodeStatus) - Fixed array of status by color index
Methods:
- Get(color string) *ColorCodeStatus - Returns status for the given color
- Copy() *CodeStatus - Creates a deep copy
When to use:
- Tracks status of code notifications per color
Status for a specific code color. Uses compact representation for memory efficiency.
Fields:
- LastAlertTime (int64) - Unix timestamp of last alert
- LastSuccessTime (int64) - Unix timestamp of last successful notification
- ConsecutiveFailures (uint16) - Consecutive notification failures (max 65535)
- Flags (uint8) - Bitfield: StatusSuccess (1<<0), StatusHasError (1<<1)
Methods:
- SetSuccess(t time.Time) - Sets success status and clears failures
- SetFailure(err error) - Sets error status and increments failures
- IsSuccess() bool - Returns true if last status was success
- GetLastAlertTime() time.Time - Returns LastAlertTime as time.Time
- GetLastSuccessTime() time.Time - Returns LastSuccessTime as time.Time
- Copy() *ColorCodeStatus - Creates a deep copy
When to use:
- Used within CodeStatus fixed array
Consolidates all job storage.
Fields:
- PulseJob (jobs.Job) - Pulse job
- InterventionJob (jobs.Job) - Intervention job
Methods:
- Copy() *JobStorage - Creates a deep copy
When to use:
- Stores pre-created jobs for an entity
- Added before jobs are enqueued
Result component for pulse jobs.
Fields:
- Result (jobs.Result) - Job result
Methods:
- None
When to use:
- Added by worker pool result router
- Removed by BatchPulseResultSystem after processing
Result component for intervention jobs.
Fields:
- Result (jobs.Result) - Job result
Methods:
- None
When to use:
- Added by worker pool result router
- Removed by BatchInterventionResultSystem after processing
Result component for code notification jobs.
Fields:
- Result (jobs.Result) - Job result
Methods:
- None
When to use:
- Added by worker pool result router
- Removed by BatchCodeResultSystem after processing
Interface for system loggers.
Methods:
- Info(format string, args ...interface{})
- Debug(format string, args ...interface{})
- Warn(format string, args ...interface{})
- Error(format string, args ...interface{})
- LogSystemPerformance(name string, duration time.Duration, count int)
When to use:
- Interface for injecting loggers into systems
Tracks entity state transitions.
Fields:
- All fields are unexported
Methods:
- LogStateChange(entityID uint32, component string, action string)
- LogSystemMetrics(systemName string, processed int, duration time.Duration)
When to use:
- Debugging state transitions
- Performance analysis
Configuration for memory-efficient system.
Fields:
- MaxEntities (int) - Maximum entities
- PreAllocate (bool) - Pre-allocate memory
Methods:
- None (data struct)
When to use:
- Configuring MemoryEfficientSystem
Memory statistics.
Fields:
- AllocatedEntities (int) - Allocated entities
- ActiveEntities (int) - Active entities
- MemoryUsage (int64) - Memory usage in bytes
Methods:
- None (data struct)
When to use:
- Returned by MemoryEfficientSystem for monitoring
Error when no pulse job is found for an entity.
Fields:
- EntityID (uint32) - Entity ID
Methods:
- Error() string
When to use:
- Error handling in pulse systems
Error when pulse job times out.
Fields:
- EntityID (uint32) - Entity ID
- Timeout (time.Duration) - Timeout duration
Methods:
- Error() string
When to use:
- Error handling in pulse systems
