leadership

package
v0.2.0-alpha.1 Latest Latest
Warning

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

Go to latest
Published: Jul 5, 2026 License: Apache-2.0 Imports: 2 Imported by: 0

README

pkg/controller/leadership

Helpers for the controller's leader-only / all-replica component split.

Overview

The controller has a small but recurring problem: leader-only components subscribe to the EventBus after all-replica components have already published critical state (config validated, HAProxy pods discovered, last template rendered). When a new leader is elected, those leader-only components have no events queued — they'd sit idle until the next reconciliation.

StateReplayer[T] solves this. All-replica components cache their most recent event of type T here; on BecameLeaderEvent the new leader's components ask the replayer to re-publish the cached event so they get current state immediately instead of waiting.

Quick Start

import (
    "gitlab.com/haproxy-haptic/haptic/pkg/controller/events"
    "gitlab.com/haproxy-haptic/haptic/pkg/controller/leadership"
)

// All-replica side (e.g. configchange.ConfigChangeHandler):
configReplayer := leadership.NewStateReplayer[*events.ConfigValidatedEvent](bus)

// On every successful validation, cache the event:
configReplayer.Cache(validatedEvent)

// Leader-only side (e.g. configpublisher.Component):
//   When BecameLeaderEvent fires, ask the replayer to re-publish.
//   The leader-only component gets the same event the rest of the
//   cluster saw most recently.
configReplayer.Replay()

The cache is a single slot — only the most recent event is retained. That's deliberate: a new leader needs the current state, not a history.

API

type StateReplayer[T busevents.Event] struct { /* opaque */ }

func NewStateReplayer[T busevents.Event](bus *busevents.EventBus) *StateReplayer[T]

func (r *StateReplayer[T]) Cache(event T)            // store the event
func (r *StateReplayer[T]) Replay() bool             // re-publish; false if nothing cached
func (r *StateReplayer[T]) HasState() bool           // peek without replay
func (r *StateReplayer[T]) Get() (T, bool)           // read the cached event without replay

All methods are safe for concurrent access via an internal RWMutex.

Where It's Used

Grep for leadership.NewStateReplayer[ to find the canonical list. Currently:

Replayed event Cache site Replay trigger
*ConfigValidatedEvent pkg/controller/configchange.ConfigChangeHandler BecameLeaderEvent consumed by leader-only configpublisher / deployer
*HAProxyPodsDiscoveredEvent pkg/controller/discovery.Component same

Render and validation events are not replayed: the render-validate path is the synchronous pkg/controller/pipeline.Pipeline, driven by the leader-only reconciler.Coordinator. The Reconciler triggers a fresh reconciliation on BecameLeaderEvent instead of replaying a stale render or validation.

See pkg/controller/LEADER_ONLY_COMPONENTS.md for the full inventory of leader-only components and the cache/replay contract every one of them implements.

See Also

License

Apache-2.0 — see root LICENSE.

Documentation

Overview

Package leadership provides utilities for handling leadership transitions in event-driven components.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type StateReplayer

type StateReplayer[T busevents.Event] struct {
	// contains filtered or unexported fields
}

StateReplayer caches the latest event of type T and re-publishes it on demand (typically in response to BecameLeaderEvent).

This solves the "late subscriber problem" where leader-only components start subscribing AFTER all-replica components have already published critical state events. By caching and replaying the last state, new leaders receive the current state immediately.

Thread-safe for concurrent access.

func NewStateReplayer

func NewStateReplayer[T busevents.Event](eventBus *busevents.EventBus) *StateReplayer[T]

NewStateReplayer creates a new StateReplayer that publishes replay events to the given EventBus.

func (*StateReplayer[T]) Cache

func (r *StateReplayer[T]) Cache(event T)

Cache stores the event for later replay. Only the latest event is retained (previous events are overwritten).

func (*StateReplayer[T]) Get

func (r *StateReplayer[T]) Get() (T, bool)

Get returns the cached event and whether it exists.

func (*StateReplayer[T]) HasState

func (r *StateReplayer[T]) HasState() bool

HasState returns whether an event has been cached.

func (*StateReplayer[T]) Replay

func (r *StateReplayer[T]) Replay() bool

Replay re-publishes the cached event to the EventBus. Returns true if an event was replayed, false if no state was cached.

Jump to

Keyboard shortcuts

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