Documentation
¶
Overview ¶
Package reconciler implements the Reconciler component that triggers reconciliation events on resource changes.
The Reconciler is a Stage 5 controller component. It subscribes to resource change events and publishes a ReconciliationTriggeredEvent IMMEDIATELY for each one — there is no reconciler-level refractory/debounce. Batching of rapid changes happens upstream, per watched-resource kind (the pkg/k8s/watcher leading-edge debouncer; default 100ms, EndpointSlice "0"), and reload throttling happens downstream (the deployer's minDeploymentInterval, which the runtime-eligible fast path bypasses). Keeping the reconciler immediate means a runtime-eligible endpoint change reaches the deployer with no latency added by this layer.
Index ¶
Constants ¶
const ( // CoordinatorComponentName is the unique identifier for the ReconciliationCoordinator. CoordinatorComponentName = "reconciliation-coordinator" // CoordinatorEventBufferSize bounds transport to the independently drained mailbox. CoordinatorEventBufferSize = busevents.ResourceChurnSubscriberBuffer )
const ComponentName = "reconciler"
ComponentName is the unique identifier for this component.
const EventBufferSize = busevents.ResourceChurnSubscriberBuffer
EventBufferSize is the size of the event subscription buffer.
One resource-index update per watcher per debounce window, which a bulk apply or a namespace teardown delivers in the hundreds. The handler only logs and publishes a trigger, so it is not slow — the burst is simply wider than 100, and this subscriber is critical, so one drop ends the controller iteration and the fleet loses its routing until it rebuilds (measured in e2e). Same input volume as the Coordinator downstream, which has been sized for the burst all along.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Coordinator ¶
type Coordinator struct {
*component.ReadySignal
// contains filtered or unexported fields
}
Coordinator orchestrates reconciliation by calling the Pipeline directly.
Render and validate run synchronously inside Pipeline.Execute() (ADR-0001 — no event hop), and the Coordinator publishes the appropriate events for downstream consumers based on the result.
Flow:
- ReconciliationTriggeredEvent received
- Publish ReconciliationStartedEvent
- Call Pipeline.Execute() (renders and validates)
- If success: Publish TemplateRenderedEvent
- If failure: Publish ReconciliationFailedEvent
The DeploymentScheduler still operates event-driven, receiving TemplateRenderedEvent and the render gate's RenderGateCompletedEvent 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.
NOTE: deliberately NOT converted to embed component.Base. Base subscribes at construction, but the coordinator is a leader-only component whose input (ReconciliationTriggeredEvent) is published by the all-replica Reconciler on EVERY replica — a constructor-time subscription would have follower replicas fill the buffer and log critical drops continuously. Subscribing here, on leadership, keeps followers unsubscribed entirely.
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
// CurrentFiles owns the last accepted auxiliary output for each leader term.
CurrentFiles CurrentFilesAuthority
// HTTPAcceptance is the HTTP store's reversible content acceptance; nil
// without an HTTP store.
HTTPAcceptance HTTPContentAcceptance
// GraphWarm reports whether the render service holds a committed graph;
// it labels failed renders. Nil counts them as warm.
GraphWarm func() bool
// Metrics receives one render count per reconcile; optional.
Metrics *metrics.Metrics
// Logger is the structured logger.
Logger *slog.Logger
}
CoordinatorConfig contains configuration for creating a Coordinator.
type CurrentFilesAuthority ¶
type CurrentFilesAuthority interface {
BeginTerm() uint64
EndTerm(generation uint64)
Snapshot(generation uint64) (map[string]string, error)
AcceptOutput(generation uint64, output *renderoutput.Snapshot) error
ConfirmOutput(generation uint64, output *renderoutput.Snapshot) error
RollbackOutput(generation uint64, output *renderoutput.Snapshot) error
}
CurrentFilesAuthority binds exact render outputs to a leader term.
type HTTPContentAcceptance ¶
type HTTPContentAcceptance interface {
AcceptanceSequence() uint64
ConfirmAcceptances(observations []httpstore.ObservationToken)
RevokeAcceptances(sequence uint64) int
}
HTTPContentAcceptance is the HTTP store's reversible acceptance (ADR-0030).
type PipelineExecutor ¶
type PipelineExecutor interface {
Execute(ctx context.Context, provider stores.StoreProvider, mode rendercontext.RenderMode, extraOpts ...rendercontext.Option) (*pipeline.PipelineResult, error)
}
PipelineExecutor defines the interface for executing the render-validate pipeline. This allows mocking in tests.
type Reconciler ¶
Reconciler triggers reconciliation immediately on every resource/HTTP change.
There is NO reconciler-level debounce. Rapid changes are batched upstream by the per-watcher debouncer (pkg/k8s/watcher), and reload-inducing structural deploys are throttled downstream by the deployer's minDeploymentInterval (which the runtime-eligible fast path skips). Firing immediately here ensures runtime-eligible endpoint changes (e.g. EndpointSlice watchers with debounceInterval: "0") propagate with no added latency. All trigger paths fire immediately:
- ResourceIndexUpdatedEvent → "resource_change"
- HTTPResourceUpdatedEvent → "http_resource_change"
- IndexSynchronizedEvent → "index_synchronized" (initial reconciliation)
- HTTPResourceAcceptedEvent / DriftPreventionTriggeredEvent / BecameLeaderEvent → immediate command triggers
The component publishes ReconciliationTriggeredEvent to signal the Coordinator to begin a reconciliation cycle. Coalescible state-update triggers (resource_change, http_resource_change) may be superseded downstream by a newer trigger; command triggers are always processed.
func New ¶
func New(eventBus *busevents.EventBus, logger *slog.Logger) *Reconciler
New creates a new Reconciler component.
Parameters:
- eventBus: The EventBus for subscribing to events and publishing triggers
- logger: Structured logger for component logging
Returns:
- A new Reconciler instance ready to be started
func (*Reconciler) HandleEvent ¶
func (r *Reconciler) HandleEvent(event busevents.Event)
HandleEvent implements component.EventHandler: it dispatches events to their handlers, tracking processing time for the health check. Each handler triggers reconciliation immediately — there is no reconciler-level debounce.
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.