Documentation
¶
Overview ¶
Package scheduler runs on the leader and reconciles desired replica counts into Assignments: it decides WHAT should run WHERE, writing only desired state (agents converge it, T-15). The red/green deployment orchestrator (T-26) drives green placement through the same helpers.
Index ¶
- func Place(st *state.Store, rel *zatterav1.Release, envID string, n int, ...) ([]string, error)
- type Autoscaler
- type BuildDialer
- type BuildDispatcher
- type BuildDispatcherConfig
- type BuildStream
- type GRPCBuildDialer
- type LiveView
- type Orchestrator
- type RegistrySweeper
- type Retention
- type RouteBuilder
- type ScaleToZero
- type Scheduler
- type Serverless
- type SnapshotDispatcher
- type SnapshotScheduler
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Place ¶
func Place(st *state.Store, rel *zatterav1.Release, envID string, n int, exclude map[string]bool) ([]string, error)
Place selects up to n nodes to run replicas of rel (its frozen ServiceSpec) for environment envID.
It is a PURE function over state (no I/O), so it is fully table-testable. Capacity is judged by RESERVATIONS (sum of RUN assignments' declared resources), not live usage. `exclude` skips nodes entirely — the red/green orchestrator uses it to place a green set beside blue and to avoid retrying a candidate that already failed. Returns fewer than n plus an error when filters/capacity cannot satisfy the request.
Types ¶
type Autoscaler ¶
type Autoscaler struct {
// contains filtered or unexported fields
}
Autoscaler runs on the leader and adjusts each environment's effective_replicas from observed CPU/memory/RPS against its Autoscale targets (spec F7). It only writes effective_replicas; the scheduler (T-23) converges the replica count into assignments.
func NewAutoscaler ¶
func NewAutoscaler(store *raftstore.Store, live LiveView, clk clock.Clock, log *slog.Logger) *Autoscaler
NewAutoscaler builds the autoscaler.
func (*Autoscaler) Run ¶
func (a *Autoscaler) Run(ctx context.Context)
Run evaluates while this node leads, resetting hold timers on each term.
type BuildDialer ¶
type BuildDialer interface {
RunBuild(ctx context.Context, node *zatterav1.Node, req *clusterv1.RunBuildRequest) (BuildStream, error)
}
BuildDialer opens a RunBuild stream to a builder node's AgentLocalService (over the mesh in production; a fake in tests).
type BuildDispatcher ¶
type BuildDispatcher struct {
// contains filtered or unexported fields
}
BuildDispatcher assigns QUEUED builds to builder nodes, streams their events, and records the outcome durably. It runs on the leader.
func NewBuildDispatcher ¶
func NewBuildDispatcher(store *raftstore.Store, clk clock.Clock, dial BuildDialer, cfg BuildDispatcherConfig, log *slog.Logger) *BuildDispatcher
NewBuildDispatcher constructs the dispatcher.
func (*BuildDispatcher) BuildLog ¶
func (d *BuildDispatcher) BuildLog(id string) []string
BuildLog returns the buffered log lines for a build (best-effort, in-memory).
func (*BuildDispatcher) Run ¶
func (d *BuildDispatcher) Run(ctx context.Context)
Run dispatches builds while this node leads, resuming on re-election.
func (*BuildDispatcher) SetBuilderTimeout ¶
func (d *BuildDispatcher) SetBuilderTimeout(t time.Duration)
SetBuilderTimeout overrides the no-event builder-lost timeout (tests use a short window; production keeps the default).
type BuildDispatcherConfig ¶
type BuildDispatcherConfig struct {
// SourceURLBase is the control-plane blob endpoint prefix, e.g.
// "https://10.90.0.1:8443/internal/blobs/"; the tarball digest is appended.
SourceURLBase string
// RegistryAddr is the embedded registry "host:port" images push to.
RegistryAddr string
// LocalLoad means builders load images into the local Docker store instead
// of pushing to the registry (single-node/dev, T-54); deploy by tag, not by
// registry digest, since a loaded image has no registry digest.
LocalLoad bool
}
BuildDispatcherConfig carries the addresses the dispatcher stamps into build requests: where the builder fetches source and where it pushes the image.
type BuildStream ¶
type BuildStream interface {
Recv() (*clusterv1.BuildEvent, error)
}
BuildStream is the receive side of an AgentLocalService.RunBuild stream.
type GRPCBuildDialer ¶
type GRPCBuildDialer struct {
Connect func(ctx context.Context, node *zatterav1.Node) (*grpc.ClientConn, error)
}
GRPCBuildDialer is the production BuildDialer: it dials a builder node's AgentLocalService over the mesh with node mTLS. Connect supplies the per-node client connection (node cert + mesh address); it stays injectable so the daemon owns the transport details.
func (GRPCBuildDialer) RunBuild ¶
func (g GRPCBuildDialer) RunBuild(ctx context.Context, node *zatterav1.Node, req *clusterv1.RunBuildRequest) (BuildStream, error)
RunBuild opens the stream, keeping the connection alive for its lifetime.
type LiveView ¶
LiveView is the slice of livestate the autoscaler reads: the current live sample of every connected node.
type Orchestrator ¶
type Orchestrator struct {
// contains filtered or unexported fields
}
Orchestrator drives red/green Deployments through their phase machine on the leader. Every arm is idempotent and every transition is a single Apply, so a leader failover resumes from durable state (never in-memory progress).
func NewOrchestrator ¶
NewOrchestrator builds the deployment orchestrator.
func (*Orchestrator) Run ¶
func (o *Orchestrator) Run(ctx context.Context)
Run reconciles deployments while this node leads, resuming on re-election.
func (*Orchestrator) SetDrainWindow ¶
func (o *Orchestrator) SetDrainWindow(d time.Duration)
SetDrainWindow overrides the blue-drain window (0 restores the default).
type RegistrySweeper ¶
RegistrySweeper untags an image and reclaims blobs it solely referenced. The daemon wires this to the local registry (the sweep runs on the control node that hosts the blobs, never over the mesh).
type Retention ¶
type Retention struct {
// contains filtered or unexported fields
}
Retention prunes old releases (and their registry images) plus stale source tarballs on the leader.
type RouteBuilder ¶
type RouteBuilder struct {
// contains filtered or unexported fields
}
RouteBuilder builds a global RouteSnapshot from cluster state and fans it out to WatchRoutes subscribers. Every control node builds the same snapshot from its replicated state (a pure function of state), so any control node can serve the stream — no leader gating needed.
func NewRouteBuilder ¶
func NewRouteBuilder(store *raftstore.Store, clk clock.Clock, domain string, log *slog.Logger) *RouteBuilder
NewRouteBuilder constructs the route builder. domain is cfg.Domain (empty → no implicit cluster subdomains).
func (*RouteBuilder) Current ¶
func (b *RouteBuilder) Current() *clusterv1.RouteSnapshot
Current returns the latest snapshot.
func (*RouteBuilder) Run ¶
func (b *RouteBuilder) Run(ctx context.Context)
Run watches routing-relevant state and rebuilds (debounced) plus on a 15s tick, fanning each snapshot out to subscribers.
func (*RouteBuilder) Subscribe ¶
func (b *RouteBuilder) Subscribe() (int, <-chan *clusterv1.RouteSnapshot)
Subscribe registers a WatchRoutes consumer; Unsubscribe with the returned id.
func (*RouteBuilder) Unsubscribe ¶
func (b *RouteBuilder) Unsubscribe(id int)
Unsubscribe removes a subscriber.
type ScaleToZero ¶
type ScaleToZero struct {
// contains filtered or unexported fields
}
ScaleToZero cools an idle scale-to-zero environment down to zero replicas (T-69). It runs on the leader, reads per-env request activity from proxy heartbeats (livestate), and sets effective_replicas=0 once an env has been idle past its idle_timeout — the scheduler then stops the replicas. Waking a cold env back up is the activator's job (T-70); this loop only scales down.
func NewScaleToZero ¶
func NewScaleToZero(store *raftstore.Store, live LiveView, clk clock.Clock, log *slog.Logger) *ScaleToZero
NewScaleToZero builds the loop.
func (*ScaleToZero) Run ¶
func (s *ScaleToZero) Run(ctx context.Context)
Run evaluates while this node leads.
type Scheduler ¶
type Scheduler struct {
// contains filtered or unexported fields
}
Scheduler is the leader-only placement loop.
type Serverless ¶
type Serverless struct {
// contains filtered or unexported fields
}
Serverless autoscales max_concurrency environments off in-flight request counts (T-71): desired = ceil(total_inflight / max_concurrency), clamped to [floor, max] where floor is 0 for scale_to_zero envs (idle cools to zero, the activator wakes them) else replicas.min. It owns these envs instead of the resource autoscaler (T-61) and the scale-to-zero loop (T-69).
func NewServerless ¶
func NewServerless(store *raftstore.Store, live LiveView, clk clock.Clock, log *slog.Logger) *Serverless
NewServerless builds the loop.
func (*Serverless) Run ¶
func (s *Serverless) Run(ctx context.Context)
Run evaluates while this node leads.
type SnapshotDispatcher ¶
type SnapshotDispatcher interface {
Snapshot(ctx context.Context, vol *zatterav1.Volume) error
Prune(ctx context.Context, vol *zatterav1.Volume, deadSnapshotIDs []string) error
}
SnapshotDispatcher performs the node-side snapshot work the leader schedules: Snapshot dispatches a snapshot of the volume to its node; Prune deletes the given snapshots' manifest objects and garbage-collects orphaned chunks.
type SnapshotScheduler ¶
type SnapshotScheduler struct {
// contains filtered or unexported fields
}
SnapshotScheduler fires scheduled volume snapshots (SnapshotPolicy.schedule) on the leader and enforces keep_last retention.
func NewSnapshotScheduler ¶
func NewSnapshotScheduler(store *raftstore.Store, disp SnapshotDispatcher, clk clock.Clock, log *slog.Logger) *SnapshotScheduler
NewSnapshotScheduler builds the scheduler.
func (*SnapshotScheduler) Run ¶
func (s *SnapshotScheduler) Run(ctx context.Context)
Run evaluates while this node leads.