controller

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Aug 3, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DeploymentControllerFinalizer = "agentregistry.dev/deployment-controller"
	DeploymentForceAnnotation     = "reconcile.agentregistry.dev/force"
)

Variables

View Source
var ErrControllerNotReady = errors.New("deployment controller is not ready")

ErrControllerNotReady is returned until Refresh completes successfully.

Functions

This section is empty.

Types

type ControlPlaneEventReader

type ControlPlaneEventReader interface {
	ListAfter(ctx context.Context, afterRevision int64, limit int) ([]v1alpha1store.ControlPlaneEvent, error)
	OldestRevision(ctx context.Context) (revision int64, ok bool, err error)
	CurrentRevision(ctx context.Context) (int64, error)
}

ControlPlaneEventReader is the durable event-log surface the controller uses to replay source invalidations.

type ControllerConfig

type ControllerConfig struct {
	Retention                  RetentionPolicy
	DiscoveryInterval          time.Duration
	DiscoveryStaleAfterMisses  int
	DiscoveryDeleteAfterMisses int
	DependencyKinds            map[string]bool
}

ControllerConfig controls optional controller maintenance loops.

type ControllerHandle

type ControllerHandle struct {
	Controller *DeploymentController
	Discovery  *DeploymentDiscoveryController
	Retention  *RetentionPruner
}

ControllerHandle owns the always-on Deployment controller loops.

func StartDeploymentController

func StartDeploymentController(
	ctx context.Context,
	pool *pgxpool.Pool,
	stores map[string]*v1alpha1store.Store,
	adapters map[string]types.DeploymentAdapter,
	config ControllerConfig,
) (*ControllerHandle, error)

StartDeploymentController constructs the Deployment controller, runs the initial refresh synchronously, and starts reconcile/execution loops in the background. The returned handle is useful in tests and future health wiring.

type DeploymentController

type DeploymentController struct {
	Stores   map[string]*v1alpha1store.Store
	Adapters map[string]types.DeploymentAdapter
	Getter   v1alpha1.GetterFunc
	Events   ControlPlaneEventReader

	BatchLimit int
	Wakeups    <-chan struct{}
	Queue      workqueue.TypedRateLimitingInterface[deploymentQueueKey]
	// DependencyKinds extends the built-in resource kinds whose durable events
	// requeue Deployments. Fingerprint gating prevents unchanged adapter work.
	DependencyKinds map[string]bool
	// contains filtered or unexported fields
}

DeploymentController replays durable source invalidations and reconciles Deployments through an in-memory workqueue. Source state remains durable in the v1alpha1 tables and control_plane_events; queued work is intentionally process-local and rebuilt by startup/repair full reconciles.

func (*DeploymentController) Checkpoint

func (c *DeploymentController) Checkpoint() int64

Checkpoint returns the last fully handled event revision.

func (*DeploymentController) Drain

Drain replays retained events after the internal checkpoint. If pruning created a gap, it falls back to Refresh.

func (*DeploymentController) FullReconcile

func (c *DeploymentController) FullReconcile(ctx context.Context) (int, error)

FullReconcile schedules work for every current Deployment, including terminating rows that still need finalizer-driven teardown.

func (*DeploymentController) HandleEvent

HandleEvent maps a source invalidation to Deployment work. Dependency changes intentionally use a full Deployment scan for this first controller foundation. Agent harness composition refs (Plugins, Skills, and Prompt instructions) and Model selection are dependency events so changes requeue Deployments that may depend on their resolved state.

func (*DeploymentController) ReadinessError

func (c *DeploymentController) ReadinessError() error

ReadinessError explains why callers should not trust the controller state.

func (*DeploymentController) Ready

func (c *DeploymentController) Ready() bool

Ready reports whether the controller has completed an initial refresh.

func (*DeploymentController) Refresh

Refresh performs a full repair pass. It captures the durable event high-water mark before rebuilding Deployment work, then replays anything newer so writes racing the refresh are not skipped.

func (*DeploymentController) Run

func (c *DeploymentController) Run(ctx context.Context, resyncInterval time.Duration) error

Run keeps Deployment reconciliation repaired. Wakeups should be wired to coarse database invalidations; the resync ticker is a periodic safety refresh. Adapter side effects run through the in-memory workqueue worker.

func (*DeploymentController) RunOnce

func (c *DeploymentController) RunOnce(ctx context.Context) (int, error)

RunOnce processes at most one currently ready queued Deployment key. It is primarily a test hook; RunWorker owns the blocking production loop.

func (*DeploymentController) RunWorker

func (c *DeploymentController) RunWorker(ctx context.Context) error

RunWorker processes queued Deployment keys until the queue is shut down.

func (*DeploymentController) Sync

func (c *DeploymentController) Sync(ctx context.Context, checkpoint int64) (SyncResult, error)

Sync replays retained events after checkpoint. If pruning created a gap, it performs a full refresh and then replays newer events.

type DeploymentDiscoveryController

type DeploymentDiscoveryController struct {
	Stores            map[string]*v1alpha1store.Store
	Adapters          map[string]types.DeploymentAdapter
	StaleAfterMisses  int
	DeleteAfterMisses int
}

DeploymentDiscoveryController materializes adapter discovery snapshots into persisted Deployment rows. It owns provider-observed state; the normal DeploymentController skips these rows so they do not become desired state.

func (*DeploymentDiscoveryController) Run

func (*DeploymentDiscoveryController) Sync

type DeploymentDiscoverySyncResult

type DeploymentDiscoverySyncResult struct {
	Runtimes   int
	Discovered int
	// Stale counts discovered rows currently at or past the consecutive-miss
	// staleness threshold (their Discovered/Ready conditions are False).
	Stale int
	// Removed counts discovered rows deleted this pass — either past the
	// consecutive-miss deletion threshold or orphaned by Runtime deletion.
	Removed int
}

DeploymentDiscoverySyncResult summarizes one discovery materialization pass.

type PluginController

type PluginController struct {
	Store    pluginStore
	Resolver source.Resolver
	Wakeups  <-chan struct{}
	// contains filtered or unexported fields
}

PluginController reconciles Plugin resources out of band of the API write: it resolves each plugin's pinned source pointer (a git commit or — later — an OCI digest) to a concrete commit/digest, scans the source for its manifest and inventory, and records all of it in PluginStatus. It stores NOTHING: the bundle stays at its origin and is materialized from source at deploy time.

It is level-triggered — every control-plane wakeup (and the resync tick) re-lists plugins and enqueues those whose status is behind their generation. Status writes never re-emit control-plane events (the trigger skips spec-equal updates), so the controller does not wake itself. Each controller opens its OWN control-plane LISTEN subscription (the Deployment controller has a separate one); there is no shared listen loop.

func NewPluginController

func NewPluginController(
	pool *pgxpool.Pool,
	stores map[string]*v1alpha1store.Store,
	deps PluginControllerDeps,
) (*PluginController, error)

NewPluginController wires the Plugin controller without starting it. Start owns the background goroutine and control-plane LISTEN subscription.

func (*PluginController) Run

func (c *PluginController) Run(ctx context.Context, resync time.Duration) error

Run drives the controller loop until ctx is cancelled.

func (*PluginController) Start

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

Start begins the Plugin controller's background reconcile loop. It owns the goroutine and opens this controller's control-plane LISTEN subscription.

func (*PluginController) Stop

func (c *PluginController) Stop()

Stop requests the Plugin controller's background loop to exit and waits for it to stop. A controller is single-use; construct a new one to start again.

type PluginControllerDeps

type PluginControllerDeps struct {
	Resolver source.Resolver
}

PluginControllerDeps are the Plugin controller's dependencies. Resolver pins a plugin's source pointer and loads its bundle; it is required.

type PruneStores

type PruneStores struct {
	ControlPlaneEvents interface {
		PruneBefore(ctx context.Context, before time.Time, keepAfterRevision int64, limit int) (int64, error)
	}
}

PruneStores groups the store surfaces needed by RunRetentionPrune. Keeping these as tiny interfaces lets the controller package stay independent from concrete Postgres store construction and keeps tests cheap.

type ReconcileAction

type ReconcileAction string

ReconcileAction is the operation implied by a Deployment's current source state.

const (
	// ReconcileActionApply converges a Deployment toward running desired state.
	ReconcileActionApply ReconcileAction = "apply"
	// ReconcileActionDelete tears down runtime resources for an undeploy/delete.
	ReconcileActionDelete ReconcileAction = "delete"
)

type RetentionPolicy

type RetentionPolicy struct {
	ControlPlaneEvents time.Duration
	EventKeepAfterRev  int64
	BatchLimit         int
}

RetentionPolicy is the bounded-history contract for the controller event replay log. Durations <= 0 disable pruning.

func (RetentionPolicy) Enabled

func (p RetentionPolicy) Enabled() bool

Enabled reports whether the policy prunes the controller event log.

type RetentionPruneResult

type RetentionPruneResult struct {
	ControlPlaneEvents int64
}

RetentionPruneResult reports how many event rows were removed in one maintenance pass.

func RunRetentionPrune

func RunRetentionPrune(ctx context.Context, stores PruneStores, policy RetentionPolicy, now time.Time) (RetentionPruneResult, error)

RunRetentionPrune applies a RetentionPolicy to the controller event log. Canonical resource tables remain the source of truth, so controllers can full-reconcile if their checkpoint falls behind the retained event range.

type RetentionPruner

type RetentionPruner struct {
	Stores PruneStores
	Policy RetentionPolicy
	Now    func() time.Time
}

RetentionPruner owns the periodic maintenance loop for controller event replay rows.

func (*RetentionPruner) Enabled

func (p *RetentionPruner) Enabled() bool

func (*RetentionPruner) Run

func (p *RetentionPruner) Run(ctx context.Context, interval time.Duration) error

func (*RetentionPruner) RunOnce

type SkillController

type SkillController struct {
	Store   skillStore
	Resolve SkillResolveFunc
	Wakeups <-chan struct{}
	// contains filtered or unexported fields
}

SkillController reconciles Skill resources out of band of the API write: it resolves each skill's pinned git source ref to a concrete commit and records it in SkillStatus.ResolvedSource. It stores NOTHING: the skill content stays at its origin and is materialized from source at deploy time. It mirrors the Plugin controller's resolve-and-pin model, minus the manifest/inventory scan (a skill has no bundle to enumerate).

It is level-triggered — every control-plane wakeup (and the resync tick) re-lists skills and enqueues those whose status is behind their generation. Status writes never re-emit control-plane events (the trigger skips spec-equal updates), so the controller does not wake itself. Each controller opens its OWN control-plane LISTEN subscription.

func NewSkillController

func NewSkillController(
	pool *pgxpool.Pool,
	stores map[string]*v1alpha1store.Store,
	deps SkillControllerDeps,
) (*SkillController, error)

NewSkillController wires the Skill controller without starting it. Start owns the background goroutine and control-plane LISTEN subscription.

func (*SkillController) Run

func (c *SkillController) Run(ctx context.Context, resync time.Duration) error

Run drives the controller loop until ctx is cancelled.

func (*SkillController) Start

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

Start begins the Skill controller's background reconcile loop. It owns the goroutine and opens this controller's control-plane LISTEN subscription.

func (*SkillController) Stop

func (c *SkillController) Stop()

Stop requests the Skill controller's background loop to exit and waits for it to stop. A controller is single-use; construct a new one to start again.

type SkillControllerDeps

type SkillControllerDeps struct {
	Resolve SkillResolveFunc
}

SkillControllerDeps are the Skill controller's dependencies. Resolve pins a skill's git source ref to a commit; it defaults to a git ls-remote resolver when nil.

type SkillResolveFunc

type SkillResolveFunc func(ctx context.Context, repo *v1alpha1.Repository) (commit string, err error)

SkillResolveFunc resolves a skill's git source ref to a concrete commit SHA. It is the only I/O-bearing dependency of the Skill controller, so tests inject a fake instead of touching the network.

type SyncResult

type SyncResult struct {
	Checkpoint   int64
	Events       int
	FullResynced bool
}

SyncResult describes one controller replay pass.

Jump to

Keyboard shortcuts

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