Help us shape the future of Go! Take the 2026 Go Developer Survey

cluster

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Oct 14, 2026 License: AGPL-3.0 Imports: 6 Imported by: 0

Documentation

Overview

Package cluster is what lets several Pando processes serve one install against one database (issue #72).

Each process is a replica. A replica registers itself, heartbeats, and is taken to have stopped when it goes quiet; work it had under way is then recorded as interrupted by whichever replica leads. One replica at a time leads, and only the leader runs the jobs that must happen once per install — garbage collection, auto-deploy, audit retention — rather than once per process.

This is not scheduling (R-010). A replica is Pando's own process, never a place an app runs, and nothing here decides where a workload goes. The apps run where the runtime adapter puts them, exactly as with one replica.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Job

type Job struct {
	Name string
	Run  func(ctx context.Context)
}

Job is something the leader runs until its context ends.

type Leader

type Leader struct {
	Store  Leadership
	Jobs   []Job
	Logger *zap.Logger

	// Retry is how often a follower tries to lead, and how often a leader
	// checks it still is. Ten seconds when zero.
	Retry time.Duration
	// contains filtered or unexported fields
}

Leader runs Jobs on whichever one replica holds the leader lock.

A lock for the whole set rather than one per job: the jobs are a handful of slow loops, and one leader is one place to look when asking "who is running the GC". A replica that loses the lock cancels every job and waits for them to stop before it tries to lead again, so two never run a job at once.

func (*Leader) Leading

func (l *Leader) Leading() bool

Leading reports whether this replica leads now.

func (*Leader) Run

func (l *Leader) Run(ctx context.Context)

Run tries to lead until ctx ends.

type Leadership

type Leadership interface {
	TryLead(ctx context.Context, check time.Duration) (*state.Leadership, bool, error)
}

Leadership is the slice of state.Replicas a leader uses.

type LogOwner

type LogOwner struct {
	Self        string
	Deployments interface {
		Runner(ctx context.Context, deploymentID string) (string, error)
		Waiting(ctx context.Context, deploymentID string) (bool, error)
	}
	Replicas interface {
		ByID(ctx context.Context, replicaID string) (state.Replica, bool, error)
	}

	// ClaimWait is how long to wait for a queued deploy to be claimed before
	// answering (O-32): until then nobody holds its log, and answering "this
	// replica" would follow a log another replica is about to write. A
	// minute when zero.
	ClaimWait time.Duration
}

LogOwner finds the base URL of the live replica running a deployment, or "" when it is this replica, or no live replica is: the answer to "where is this deploy's live log" (issue #72).

func (LogOwner) Where

func (o LogOwner) Where(ctx context.Context, deploymentID string) (string, error)

Where answers for one deployment.

type Member

type Member struct {
	Store        Store
	ID           string
	Hostname     string
	AdvertiseURL string
	Version      string
	Minter       *assertion.Minter
	Logger       *zap.Logger

	// Interval is how often to heartbeat; state.HeartbeatInterval if zero.
	Interval time.Duration
}

Member is this process's membership of the install.

func (*Member) Join

func (m *Member) Join(ctx context.Context) error

Join registers this replica and publishes its signing key. Before the server listens: an assertion this replica signs must be verifiable from the first request it serves.

func (*Member) Leave

func (m *Member) Leave(ctx context.Context)

Leave records this replica as stopped, at shutdown.

func (*Member) PeerKeys

func (m *Member) PeerKeys(ctx context.Context) ([]assertion.PublicKey, error)

PeerKeys reads every replica's published key, for the JWKS.

func (*Member) Run

func (m *Member) Run(ctx context.Context) (restart string)

Run heartbeats until ctx ends, and returns early — with the reason — when this replica should restart: a restart was asked for (POST /restart reaches every replica, not only the one that received it), or the install has taken this replica for dead and abandoned its work, after which carrying on under the same identity would be a lie.

type Store

type Store interface {
	Register(ctx context.Context, rep state.Replica) error
	Heartbeat(ctx context.Context, replicaID string) (bool, error)
	Stop(ctx context.Context, replicaID string) error
	RestartPending(ctx context.Context, replicaID string) (bool, error)
	VerificationKeys(ctx context.Context, validity time.Duration) ([]state.Replica, error)
}

Store is the slice of state.Replicas a member uses.

type Sweeper

type Sweeper struct {
	Abandon []func(ctx context.Context) (int64, error)
	Prune   func(ctx context.Context) error
	Logger  *zap.Logger
	Every   time.Duration
}

Sweeper records work left by stopped replicas as interrupted, and forgets replicas long gone. A leader job.

func (*Sweeper) Run

func (s *Sweeper) Run(ctx context.Context)

Run sweeps until ctx ends.

func (*Sweeper) Sweep

func (s *Sweeper) Sweep(ctx context.Context)

Sweep is one pass.

Jump to

Keyboard shortcuts

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