Documentation
¶
Overview ¶
pkg/autoscaler/autoscale_metrics.go
AutoMetrics — live operatorbox metrics read directly from the runtime.
The autoscaler evaluates conditions against these metrics on every tick. All reads are atomic — no locks, no API calls, no informer lookups.
Metric fields are exposed under the "metrics.*" namespace in autoscale conditions and resolve through AutoMetrics.Get(field).
pkg/autoscaler/autoscale_semaphore.go
ResizableSemaphore — a weighted semaphore whose capacity can be changed at runtime.
The worker pool in Orkestra is gated by this semaphore rather than being a fixed goroutine count. All worker goroutines run continuously in a loop; the semaphore controls how many may enter the reconcile section simultaneously.
Increasing capacity: new goroutines can acquire immediately. Decreasing capacity: goroutines currently inside reconcile finish their current work. Goroutines blocked at Acquire wait until capacity is available. In-flight reconciles are never interrupted.
This is the correct primitive for operator autoscaling because:
- Resize is O(1) — no goroutine creation or cancellation
- In-flight reconciles complete cleanly after a scale-down
- The semaphore is the single source of truth for concurrency
pkg/autoscaler/autoscaler.go
Operatorbox autoscaler — evaluates conditions on a ticker and applies or restores worker/queue/resync overrides.
One Autoscaler is created per operatorbox that declares autoscale: in its operatorBox: block. It runs a single goroutine for the lifetime of the operatorbox and stops cleanly when the context is cancelled.
The autoscaler has no persistent state. A restart always begins from the declared CRD baseline. Overrides applied before a restart are lost — the next evaluation tick will re-apply them if conditions are still met.
Index ¶
- func IsMetricField(field string) bool
- type AutoMetrics
- type AutoscaleTarget
- type Autoscaler
- type ResizableSemaphore
- func (s *ResizableSemaphore) Acquire(ctx context.Context) error
- func (s *ResizableSemaphore) BusyPercent() float64
- func (s *ResizableSemaphore) Capacity() int
- func (s *ResizableSemaphore) Current() int
- func (s *ResizableSemaphore) IdlePercent() float64
- func (s *ResizableSemaphore) InFlight() int
- func (s *ResizableSemaphore) Release()
- func (s *ResizableSemaphore) Resize(newCap int)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsMetricField ¶
IsMetricField returns true when the field path refers to an autoscale metric. Used by the condition resolver to route metric lookups to AutoMetrics.Get.
Types ¶
type AutoMetrics ¶
type AutoMetrics struct {
// contains filtered or unexported fields
}
AutoMetrics holds live operatorbox runtime metrics for autoscale evaluation. All counters are atomic int64 values — safe for concurrent read/write from worker goroutines and the autoscaler loop.
func NewAutoMetrics ¶
func NewAutoMetrics(sem *ResizableSemaphore) *AutoMetrics
NewAutoMetrics returns an initialised AutoMetrics for the given semaphore.
func (*AutoMetrics) AsMap ¶
func (m *AutoMetrics) AsMap() map[string]interface{}
func (*AutoMetrics) ErrorRatePercent ¶
func (m *AutoMetrics) ErrorRatePercent() float64
ErrorRatePercent returns the curent error rate i percentage
func (*AutoMetrics) Get ¶
func (m *AutoMetrics) Get(field string) string
Get returns the string representation of a metric field for condition evaluation. Field names follow the metrics.* convention:
metrics.workersBusyPercent → "73.5" metrics.workersIdlePercent → "26.5" metrics.queueDepth → "342" metrics.reconcileDurationP95Ms → "47" metrics.errorRatePercent → "0.2"
Returns "" for unknown fields — evaluates as notExists in condition checks.
func (*AutoMetrics) RecordReconcile ¶
func (m *AutoMetrics) RecordReconcile(duration time.Duration, failed bool)
RecordReconcile records one completed reconcile with its duration and outcome. Called at the end of every reconcile, success or failure.
func (*AutoMetrics) SetQueueDepth ¶
func (m *AutoMetrics) SetQueueDepth(depth int64)
SetQueueDepth updates the current queue depth. Called by the workqueue wrapper on every enqueue and dequeue.
type AutoscaleTarget ¶
type AutoscaleTarget interface {
// ResizeWorkers adjusts the worker pool to the given concurrency.
ResizeWorkers(n int)
// SetQueueDepthLimit adjusts the maximum queue depth.
SetQueueDepthLimit(n int)
// SetResyncInterval adjusts how frequently all CRs are re-enqueued.
SetResyncInterval(d time.Duration)
}
AutoscaleTarget is implemented by the operatorbox runtime components that the autoscaler controls. Kept minimal — autoscaler only calls these three methods, nothing else.
type Autoscaler ¶
type Autoscaler struct {
// contains filtered or unexported fields
}
Autoscaler evaluates conditions and applies/restores overrides for one operatorbox.
func NewAutoscaler ¶
func NewAutoscaler( crdKind string, spec *orktypes.AutoscaleSpec, baseline orktypes.AutoscaleBaseline, target AutoscaleTarget, metrics *AutoMetrics, ) *Autoscaler
NewAutoscaler constructs an Autoscaler for one operatorbox. baseline is captured from the CRD's declared configuration before startup.
func (*Autoscaler) Run ¶
func (a *Autoscaler) Run(ctx context.Context)
Run starts the autoscale evaluation loop. Blocks until ctx is cancelled. Intended to be called in a dedicated goroutine.
type ResizableSemaphore ¶
type ResizableSemaphore struct {
// contains filtered or unexported fields
}
ResizableSemaphore is a counting semaphore whose capacity can be changed at runtime without interrupting goroutines currently holding a token.
func NewResizableSemaphore ¶
func NewResizableSemaphore(capacity int) *ResizableSemaphore
NewResizableSemaphore returns a semaphore with the given initial capacity.
func (*ResizableSemaphore) Acquire ¶
func (s *ResizableSemaphore) Acquire(ctx context.Context) error
Acquire acquires one token, blocking until one is available or ctx is done. Returns ctx.Err() if the context is cancelled while waiting.
func (*ResizableSemaphore) BusyPercent ¶
func (s *ResizableSemaphore) BusyPercent() float64
BusyPercent returns the percentage of capacity currently in use.
func (*ResizableSemaphore) Capacity ¶
func (s *ResizableSemaphore) Capacity() int
Capacity returns the current capacity.
func (*ResizableSemaphore) Current ¶
func (s *ResizableSemaphore) Current() int
Current returns the current number of tokens.
func (*ResizableSemaphore) IdlePercent ¶
func (s *ResizableSemaphore) IdlePercent() float64
IdlePercent returns the percentage of capacity currently available.
func (*ResizableSemaphore) InFlight ¶
func (s *ResizableSemaphore) InFlight() int
InFlight returns the number of tokens currently held (goroutines inside reconcile).
func (*ResizableSemaphore) Release ¶
func (s *ResizableSemaphore) Release()
Release releases one token and notifies a waiter if any are queued.
func (*ResizableSemaphore) Resize ¶
func (s *ResizableSemaphore) Resize(newCap int)
Resize changes the semaphore capacity.
Scale up (newCap > old): immediately notifies waiting goroutines up to the new capacity. Each notification allows one waiter to proceed.
Scale down (newCap < old): the new capacity takes effect immediately for new Acquire calls. Goroutines already holding tokens complete their work normally — they are not interrupted. The effective concurrency converges to newCap as holders release.
Resize is safe to call concurrently with Acquire and Release.