reconciler

package
v0.1.0-alpha.12 Latest Latest
Warning

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

Go to latest
Published: Feb 27, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

README

pkg/controller/reconciler

Reconciler component - debounces resource changes and triggers reconciliation.

Overview

Stage 5 component that applies debouncing logic to prevent excessive reconciliations. Waits for quiet periods before triggering reconciliation events.

Features

  • Debouncing: Batches rapid resource changes
  • Immediate initial sync: Triggers reconciliation when all resources synced
  • Configurable interval: Default 5s
  • Initial sync filtering: Ignores initial resource sync events

Quick Start

import "haptic/pkg/controller/reconciler"

// Default configuration (5s debounce)
reconciler := reconciler.New(bus, logger, nil)
go reconciler.Start(ctx)

// Custom debounce interval
reconciler := reconciler.New(bus, logger, &reconciler.Config{
    DebounceInterval: 2 * time.Second,
})
go reconciler.Start(ctx)

How It Works

Resource Changes (Debounced)
  1. ResourceIndexUpdatedEvent received
  2. Debounce timer reset to 5s
  3. If another change arrives, timer reset again
  4. When timer expires (no changes for 5s), publish ReconciliationTriggeredEvent
Index Synchronized (Immediate)
  1. IndexSynchronizedEvent received (all resource watchers synced)
  2. Stop any pending debounce timer
  3. Immediately publish ReconciliationTriggeredEvent

This triggers the initial reconciliation after all resources are indexed, ensuring the first render has a complete view of cluster state.

Events

Subscribes To
  • ResourceIndexUpdatedEvent: Resource change (debounced)
  • IndexSynchronizedEvent: All resources synced (immediate)
  • HTTPResourceUpdatedEvent: HTTP content change (debounced)
  • HTTPResourceAcceptedEvent: HTTP content accepted (immediate)
  • DriftPreventionTriggeredEvent: Drift prevention (immediate)
Publishes
  • ReconciliationTriggeredEvent: Reconciliation requested

Configuration

type Config struct {
    DebounceInterval time.Duration  // Default: 5s
}

Constants

const (
    DefaultDebounceInterval = 5 * time.Second
    EventBufferSize        = 100
)

Example Timing

t=0ms:    Resource change → Start 5s timer
t=100ms:  Resource change → Reset timer (now expires at t=5100ms)
t=300ms:  Resource change → Reset timer (now expires at t=5300ms)
t=5300ms: Timer expires → Trigger reconciliation

Result: 3 changes batched into 1 reconciliation.

License

See main repository for license information.

Documentation

Overview

Package reconciler implements the Reconciler component that debounces resource changes and triggers reconciliation events.

The Reconciler is a key component in Stage 5 of the controller startup sequence. It subscribes to resource change events, applies debouncing to batch rapid changes, and publishes reconciliation trigger events when the system reaches a quiet state.

Index

Constants

View Source
const (
	// CoordinatorComponentName is the unique identifier for the ReconciliationCoordinator.
	CoordinatorComponentName = "reconciliation-coordinator"

	// CoordinatorEventBufferSize is the size of the event subscription buffer.
	CoordinatorEventBufferSize = 50
)
View Source
const ComponentName = "reconciler"

ComponentName is the unique identifier for this component.

View Source
const (
	// EventBufferSize is the size of the event subscription buffer.
	// Size 100: Medium-volume component that receives resource change events from
	// multiple watchers (Ingress, HTTPRoute, Service, Endpoints, Secrets, ConfigMaps).
	// Higher than deployer to handle bursts when many resources change simultaneously.
	EventBufferSize = 100
)

Variables

View Source
var DefaultDebounceInterval = types.DefaultDebounceInterval

DefaultDebounceInterval is re-exported from types for backward compatibility. New code should use types.DefaultDebounceInterval directly.

Functions

This section is empty.

Types

type Config

type Config struct {
	// DebounceInterval is the minimum time between reconciliation triggers (refractory period).
	// The first change triggers immediately, subsequent changes within this interval are batched.
	// If not set, DefaultDebounceInterval is used.
	DebounceInterval time.Duration
}

Config configures the Reconciler component.

type Coordinator

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

Coordinator orchestrates reconciliation by calling the Pipeline directly.

This component replaces the event-driven flow where Renderer and Validator are separate components publishing events. Instead, it calls Pipeline.Execute() synchronously and publishes the appropriate events for downstream components.

Flow:

  1. ReconciliationTriggeredEvent received
  2. Publish ReconciliationStartedEvent
  3. Call Pipeline.Execute() (renders and validates)
  4. If success: Publish TemplateRenderedEvent + ValidationCompletedEvent
  5. If failure: Publish ReconciliationFailedEvent

The DeploymentScheduler still operates event-driven, receiving TemplateRenderedEvent and ValidationCompletedEvent to schedule deployments.

func NewCoordinator

func NewCoordinator(cfg *CoordinatorConfig) *Coordinator

NewCoordinator creates a new ReconciliationCoordinator.

Note: eventChan is NOT subscribed here - subscription happens in Start(). This is a leader-only component that subscribes when Start() is called (after leadership is acquired). All-replica components replay their state on BecameLeaderEvent to ensure leader-only components receive current state.

Parameters:

  • cfg: Configuration for the coordinator

Returns:

  • A new Coordinator instance ready to be started

func (*Coordinator) Name

func (c *Coordinator) Name() string

Name returns the unique identifier for this component.

func (*Coordinator) Start

func (c *Coordinator) Start(ctx context.Context) error

Start begins the coordinator's event loop.

This method blocks until the context is cancelled.

func (*Coordinator) SubscriptionReady

func (c *Coordinator) SubscriptionReady() <-chan struct{}

SubscriptionReady returns a channel that is closed when the component has completed its event subscription. This implements lifecycle.SubscriptionReadySignaler.

type CoordinatorConfig

type CoordinatorConfig struct {
	// EventBus is the event bus for subscribing to events and publishing results.
	EventBus *busevents.EventBus

	// Pipeline is the render-validate pipeline to execute.
	// Must implement PipelineExecutor interface.
	Pipeline PipelineExecutor

	// StoreProvider provides access to resource stores.
	StoreProvider stores.StoreProvider

	// Logger is the structured logger.
	Logger *slog.Logger
}

CoordinatorConfig contains configuration for creating a Coordinator.

type PipelineExecutor

type PipelineExecutor interface {
	Execute(ctx context.Context, provider stores.StoreProvider) (*pipeline.PipelineResult, error)
}

PipelineExecutor defines the interface for executing the render-validate pipeline. This allows mocking in tests.

type Reconciler

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

Reconciler implements the reconciliation debouncer component.

It subscribes to resource change events and index synchronization events, applies debouncing logic to prevent excessive reconciliations, and triggers reconciliation when appropriate.

Debouncing behavior (leading-edge with refractory period):

  • First change after refractory: Trigger immediately (0ms delay)
  • Changes during refractory: Queued (timer NOT reset, fires at refractory end)
  • Index synchronized: Trigger immediately (initial reconciliation after all resources synced)

This guarantees:

  • Minimum interval: At least debounceInterval between any two triggers
  • Maximum latency: Every change synced within debounceInterval

The component publishes ReconciliationTriggeredEvent to signal the Executor to begin a reconciliation cycle.

func New

func New(eventBus *busevents.EventBus, logger *slog.Logger, config *Config) *Reconciler

New creates a new Reconciler component.

Parameters:

  • eventBus: The EventBus for subscribing to events and publishing triggers
  • logger: Structured logger for component logging
  • config: Optional configuration (nil for defaults)

Returns:

  • A new Reconciler instance ready to be started

func (*Reconciler) HealthCheck

func (r *Reconciler) HealthCheck() error

HealthCheck implements the lifecycle.HealthChecker interface. Returns an error if the component appears to be stalled (processing for > timeout). Returns nil when idle (not processing) - idle is always healthy for event-driven components.

func (*Reconciler) Name

func (r *Reconciler) Name() string

Name returns the unique identifier for this component. Implements the lifecycle.Component interface.

func (*Reconciler) Start

func (r *Reconciler) Start(ctx context.Context) error

Start begins the reconciler's event loop.

This method blocks until the context is cancelled or an error occurs. The component is already subscribed to the EventBus (subscription happens in New()), so this method only processes events:

  • ResourceIndexUpdatedEvent: Leading-edge trigger or queue for refractory timer
  • IndexSynchronizedEvent: Triggers initial reconciliation when all resources synced
  • Refractory timer expiration: Publishes ReconciliationTriggeredEvent if pending changes

The component runs until the context is cancelled, at which point it performs cleanup and returns.

Parameters:

  • ctx: Context for cancellation and lifecycle management

Returns:

  • nil when context is cancelled (graceful shutdown)
  • Error only in exceptional circumstances

Jump to

Keyboard shortcuts

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