Set up a replicated store with server init --patroni, and watch it
init --patroni user@host ... installs PostgreSQL, Patroni and etcd on the given machines over ssh, with this one as the third etcd vote, makes the role and database, and moves the store in use into the cluster. Each step checks first, so it changes nothing on a cluster that is up. For a store of several hosts the control plane publishes each member's role, state and lag from Patroni, a stopped member as missing, prints it in ctl status, and alerts on it. Making an administrator on PostgreSQL sent a bool to an integer column; it sends an integer now. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
7a562ac1e7
commit
975c93994f
22 files changed
+1495
-43
No files matched your search
@@ -40,6 +40,8 @@ import (
|
||||
type API struct {
|
||||
// releases is where release binaries are fetched from, for upgrades.
|
||||
releases string
|
||||
// storeStatus reads a replicated store's members; nil for one database.
|
||||
storeStatus func() ([]StoreMember, error)
|
||||
// serve runs registry-to-replica jobs; nil without a mirror and a store.
|
||||
serve *modelserve.Server
|
||||
|
||||
@@ -698,6 +700,9 @@ type Usage interface {
|
||||
// SetUsage supplies the usage reporting source.
|
||||
func (a *API) SetUsage(u Usage) { a.usage = u }
|
||||
|
||||
// SetStoreStatus supplies the state of a replicated store, for the summary.
|
||||
func (a *API) SetStoreStatus(f func() ([]StoreMember, error)) { a.storeStatus = f }
|
||||
|
||||
// ScopeUsageView is one group's spend, with its quota when it has one.
|
||||
type ScopeUsageView struct {
|
||||
Scope string `json:"scope"`
|
||||
|
||||
@@ -31,6 +31,20 @@ type Summary struct {
|
||||
// IdleReplicas are serving replicas nothing has asked for in a while, which
|
||||
// on a fleet with more models than GPUs is the first place to find room.
|
||||
IdleReplicas []IdleReplica `json:"idle_replicas,omitempty"`
|
||||
// Store is the members of the store's cluster when it is replicated, and
|
||||
// StoreError why it could not be read; both empty for a single database.
|
||||
Store []StoreMember `json:"store,omitempty"`
|
||||
StoreError string `json:"store_error,omitempty"`
|
||||
}
|
||||
|
||||
// StoreMember is one member of a replicated store, as its Patroni reports it.
|
||||
type StoreMember struct {
|
||||
Name string `json:"name"`
|
||||
Host string `json:"host"`
|
||||
Role string `json:"role"`
|
||||
State string `json:"state"`
|
||||
// Lag is bytes behind the leader; -1 unknown, 0 for the leader.
|
||||
Lag int64 `json:"lag"`
|
||||
}
|
||||
|
||||
// NodeTotals counts nodes by the states that need different responses.
|
||||
@@ -107,6 +121,13 @@ const idleThreshold = 10 * time.Minute
|
||||
// Summary builds the fleet summary.
|
||||
func (a *API) Summary() Summary {
|
||||
var s Summary
|
||||
if a.storeStatus != nil {
|
||||
members, err := a.storeStatus()
|
||||
s.Store = members
|
||||
if err != nil {
|
||||
s.StoreError = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
nodes := a.Nodes()
|
||||
byClass := map[string]*ClassUse{}
|
||||
|
||||
Reference in new issue
Block a user