grpc

package
v2.2.2 Latest Latest
Warning

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

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

Documentation

Overview

grpc/control_server.go

Index

Constants

View Source
const BudgetSyncTopic = eventbridge.BudgetSyncTopic

BudgetSyncTopic is re-exported from eventbridge for backwards compatibility

View Source
const DEFAULT_ENCRYPTION_KEY = "DEFAULT_INSECURE_KEY_CHANGE_ME!!"

DEFAULT_ENCRYPTION_KEY is used when MICROGATEWAY_ENCRYPTION_KEY is not set CRITICAL SECURITY WARNING: This MUST be changed in production!

View Source
const DefaultBudgetSyncInterval = 30 * time.Second

DefaultBudgetSyncInterval is the default interval for budget sync (30 seconds)

Variables

This section is empty.

Functions

func ComputeSnapshotChecksum

func ComputeSnapshotChecksum(snapshot *pb.ConfigurationSnapshot) (string, error)

ComputeSnapshotChecksum generates a deterministic SHA-256 checksum for a ConfigurationSnapshot. It excludes volatile fields (version, snapshot_time, checksum, timestamps, usage stats) to ensure the checksum only changes when actual configuration data changes.

The checksum is computed from the protobuf-serialized bytes of the snapshot with deterministic marshaling enabled to ensure consistent byte order for maps and repeated fields.

func VerifySnapshotChecksum

func VerifySnapshotChecksum(snapshot *pb.ConfigurationSnapshot) (bool, error)

VerifySnapshotChecksum verifies that a snapshot's checksum matches the computed checksum. Returns true if the checksums match, false otherwise.

Types

type AppBudgetData

type AppBudgetData struct {
	// Usage is the current period usage in dollars
	Usage float64 `json:"usage"`

	// PeriodStart is the start of this app's budget period
	PeriodStart time.Time `json:"period_start"`

	// PeriodEnd is the end of this app's budget period
	PeriodEnd time.Time `json:"period_end"`
}

AppBudgetData contains budget usage and period info for a single app

type BudgetSyncPayload

type BudgetSyncPayload struct {
	// AppUsages maps app_id to current period usage in dollars
	// Deprecated: Use AppBudgets instead for per-app budget periods
	AppUsages map[uint32]float64 `json:"app_usages"`

	// AppBudgets maps app_id to budget data with per-app period info
	// This supports custom budget_start_date per app
	AppBudgets map[uint32]AppBudgetData `json:"app_budgets,omitempty"`

	// PeriodStart is the start of the budget period (1st of month)
	// Deprecated: Use per-app periods in AppBudgets instead
	PeriodStart time.Time `json:"period_start"`

	// PeriodEnd is the end of the budget period (last moment of month)
	// Deprecated: Use per-app periods in AppBudgets instead
	PeriodEnd time.Time `json:"period_end"`

	// ControlTimestamp is when the control server generated this payload
	// Used by edges to detect clock skew
	ControlTimestamp time.Time `json:"control_timestamp"`

	// SequenceNumber for ordering and deduplication
	SequenceNumber uint64 `json:"sequence_number"`

	// Blocks maps app_id to the reason edges must refuse the App on budget
	// grounds (Enterprise): its budget is 0, or its hard-blocking team has
	// spent its budget. Edges read a synced App budget of 0 as "no limit",
	// so this is how a zero budget reaches them. When BlocksIncluded is set
	// it is the complete set: edges replace theirs, so a released App is
	// served again.
	Blocks         map[uint32]string `json:"blocks,omitempty"`
	BlocksIncluded bool              `json:"blocks_included,omitempty"`
}

BudgetSyncPayload is the JSON payload for budget.sync events sent from control server to edge gateways to synchronize budget usage.

type BudgetSyncService

type BudgetSyncService struct {
	// contains filtered or unexported fields
}

BudgetSyncService aggregates budget usage from llm_chat_records and publishes updates to edge gateways via the event bridge.

func NewBudgetSyncService

func NewBudgetSyncService(db *gorm.DB, eventBus eventbridge.Bus) *BudgetSyncService

NewBudgetSyncService creates a new budget sync service. The interval can be configured via BUDGET_SYNC_INTERVAL environment variable.

func (*BudgetSyncService) GetSyncInterval

func (s *BudgetSyncService) GetSyncInterval() time.Duration

GetSyncInterval returns the configured sync interval (for testing)

func (*BudgetSyncService) PeriodUsage

func (s *BudgetSyncService) PeriodUsage(appID uint, periodStart time.Time) (float64, bool)

PeriodUsage returns an App's spend in dollars for the budget period starting at periodStart, as of the latest sync cycle (at most one interval old). It reports false before the first cycle, for an App the cycle did not see, or when the App's period has changed since.

func (*BudgetSyncService) SetEdgeBudgetSource

func (s *BudgetSyncService) SetEdgeBudgetSource(src EdgeBudgetSource)

SetEdgeBudgetSource makes every sync carry budget blocks and analyse Apps whose spend moved since the previous sync.

func (*BudgetSyncService) Start

func (s *BudgetSyncService) Start()

Start begins the budget sync background task. It aggregates usage and publishes to edges at the configured interval.

func (*BudgetSyncService) Stop

func (s *BudgetSyncService) Stop()

Stop gracefully stops the budget sync service.

type Config

type Config struct {
	GRPCPort    int
	GRPCHost    string
	TLSEnabled  bool
	TLSCertPath string
	TLSKeyPath  string
	// TLSConfig, when set, is used for TLS instead of TLSCertPath and
	// TLSKeyPath (and whatever TLSEnabled says): an embedding host supplies
	// its own certificates, cipher suites and minimum version.
	TLSConfig            *tls.Config
	AuthToken            string
	NextAuthToken        string
	MaxConcurrentStreams int // Maximum number of concurrent gRPC streams (default 1000)
	// EncryptionKey is the 32-character key edges use to decrypt the
	// credentials sent to them. Empty means MICROGATEWAY_ENCRYPTION_KEY.
	EncryptionKey string
	// NodeID identifies this Studio replica (pkg/cluster). It is recorded as
	// the owner of every edge stream this server holds. Empty means
	// "control", for a single replica.
	NodeID string
	// BudgetSyncInterval is how often budget usage is synced to edges.
	// Zero means BUDGET_SYNC_INTERVAL, or 30s.
	BudgetSyncInterval time.Duration

	// MaxMessageSize bounds a message in either direction, in bytes (zero:
	// 16 MB, the edge's own GRPC_MAX_MESSAGE_SIZE default). Configuration
	// snapshots and analytics pulses outgrow gRPC's 4 MB default.
	MaxMessageSize int
	// KeepaliveMinTime is the shortest interval between client pings the
	// server accepts, with or without an open stream (zero: 10s; edges ping
	// every 30s). A client pinging more often is disconnected.
	KeepaliveMinTime time.Duration
	// MaxConnectionAge, when set, closes each connection after about this
	// long, so edges spread again over replicas behind a load balancer;
	// streams get MaxConnectionAgeGrace to finish. Zero keeps connections
	// open: an edge's stream is long-lived, and pushes in flight on a closed
	// stream go back to pending.
	MaxConnectionAge      time.Duration
	MaxConnectionAgeGrace time.Duration
}

Config holds the control server configuration

type ControlServer

type ControlServer struct {
	pb.UnimplementedConfigurationSyncServiceServer
	// contains filtered or unexported fields
}

ControlServer implements the ConfigurationSyncService for AI Studio control instances

func NewControlServer

func NewControlServer(cfg *Config, db *gorm.DB) (*ControlServer, error)

NewControlServer creates a new control server for AI Studio. It fails when the microgateway encryption key is missing or insecure.

func (*ControlServer) GetEventBus

func (s *ControlServer) GetEventBus() eventbridge.Bus

GetEventBus returns the control server's event bus for subscribing to events. This allows other AI Studio components to subscribe to events from edges.

func (*ControlServer) GetFullConfiguration

func (s *ControlServer) GetFullConfiguration(ctx context.Context, req *pb.ConfigurationRequest) (*pb.ConfigurationSnapshot, error)

GetFullConfiguration retrieves a complete configuration snapshot for an edge. This is the path a reload uses (microgateway RequestFullSync). The namespace is resolved the way registration resolved it -- the registered edge's stored namespace when the edge is known, else the normalised request namespace -- so an edge whose EDGE_NAMESPACE is unset ("") pulls the same snapshot its heartbeat is compared against. The pulling edge is marked in sync at once, as the stream ConfigRequest path does, rather than waiting for a heartbeat.

func (*ControlServer) LocalStreams

func (s *ControlServer) LocalStreams() map[string]string

LocalStreams lists the edges with a live stream on this replica that are ready for pushes (see pushReady), with the stream's session.

func (*ControlServer) RegisterEdge

RegisterEdge handles edge instance registration

func (*ControlServer) SendAnalyticsPulse

func (s *ControlServer) SendAnalyticsPulse(ctx context.Context, req *pb.AnalyticsPulse) (*pb.AnalyticsPulseResponse, error)

SendAnalyticsPulse handles analytics pulse data from edge instances

func (*ControlServer) SendHeartbeat

func (s *ControlServer) SendHeartbeat(ctx context.Context, req *pb.HeartbeatRequest) (*pb.HeartbeatResponse, error)

SendHeartbeat handles unary heartbeat requests, a deprecated RPC: edges heartbeat on their stream (SubscribeToChanges), which also tracks stream ownership. The unary call is answered from the database, so it works on any replica, not only the one holding the edge's stream; it records the heartbeat and leaves ownership alone.

func (*ControlServer) SendPluginControlBatch

func (s *ControlServer) SendPluginControlBatch(ctx context.Context, req *pb.PluginControlBatch) (*pb.PluginControlBatchResponse, error)

SendPluginControlBatch handles plugin control payloads from edge instances This enables plugins running on edge (microgateway) to send data back to AI Studio control plane

func (*ControlServer) SendReload

func (s *ControlServer) SendReload(edgeID, session string, req *pb.ConfigurationReloadRequest) error

SendReload sends a push on the edge's stream, provided it is still the stream with the given session: a push must go out on the stream it was claimed for, or not at all.

func (*ControlServer) Serve

func (s *ControlServer) Serve(listener net.Listener) error

Serve serves the gRPC control server on listener until Stop is called. An embedding host uses it to supply its own listener.

func (*ControlServer) SetEdgeBudgetSource

func (s *ControlServer) SetEdgeBudgetSource(src EdgeBudgetSource)

SetEdgeBudgetSource has the budget sync push budget blocks to edges and raise budget alerts for edge spend (Enterprise).

func (*ControlServer) SetEdgePayloadForwarder

func (s *ControlServer) SetEdgePayloadForwarder(f EdgePayloadForwarder)

SetEdgePayloadForwarder has a replica without plugins (no SetPluginManager) forward edges' plugin payloads to one that has them. Set it before Serve.

func (*ControlServer) SetGovernedMetadataReader

func (s *ControlServer) SetGovernedMetadataReader(reader governed_metadata.SnapshotReader)

SetGovernedMetadataReader wires the governed metadata service so gateway-visible fields are included in configuration snapshots. Safe to leave unset (CE).

func (*ControlServer) SetPluginManager

func (s *ControlServer) SetPluginManager(manager interface{})

SetPluginManager sets the plugin manager reference for routing edge payloads

func (*ControlServer) SetPushDelivery

func (s *ControlServer) SetPushDelivery(p PushDelivery)

SetPushDelivery connects the push coordinator. The coordinator in turn uses the server's LocalStreams and SendReload.

func (*ControlServer) Start

func (s *ControlServer) Start() error

Start listens on the configured host and port and serves the gRPC control server until Stop is called.

func (*ControlServer) Stop

func (s *ControlServer) Stop()

Stop stops the gRPC server gracefully

func (*ControlServer) SubscribeToChanges

SubscribeToChanges handles bidirectional streaming for real-time updates

func (*ControlServer) UnregisterEdge

func (s *ControlServer) UnregisterEdge(ctx context.Context, req *pb.EdgeUnregistrationRequest) (*emptypb.Empty, error)

UnregisterEdge handles edge instance unregistration

func (*ControlServer) ValidateToken

ValidateToken validates an API token on-demand with namespace filtering

type EdgeBudgetSource

type EdgeBudgetSource interface {
	EdgeBlocks() (map[uint]string, error)
	AnalyzeApps(appIDs []uint)
}

EdgeBudgetSource is the Enterprise budget service as the budget sync sees it: the Apps edges must refuse, and threshold analysis for spend that reached Studio from edges (edge traffic never passes Studio's own budget check, so nothing else would raise its alerts).

type EdgeInstanceConnection

type EdgeInstanceConnection struct {
	EdgeID        string
	Namespace     string
	Status        string
	Version       string
	SessionID     string
	Stream        pb.ConfigurationSyncService_SubscribeToChangesServer
	LastHeartbeat time.Time
	// contains filtered or unexported fields
}

EdgeInstance represents an active edge instance connection

type EdgePayloadForwarder

type EdgePayloadForwarder interface {
	ForwardEdgePayloads(ctx context.Context, payloads []*pb.PluginControlPayload) error
}

EdgePayloadForwarder takes an edge's plugin payloads to another replica that hosts the plugins, for a replica without them (a headless control plane): a whole batch at once, all or none. A nil error means they are queued for that replica, not that a plugin has handled them.

type EdgePayloadRouter

type EdgePayloadRouter interface {
	RouteEdgePayload(ctx context.Context, payload *pb.PluginControlPayload) error
}

EdgePayloadRouter interface for routing edge payloads to plugins

type PushDelivery

type PushDelivery interface {
	StreamOpened(edgeID string)
	StreamClosed(edgeID, session string)
	HandleReloadResponse(*pb.ConfigurationReloadResponse)
}

PushDelivery is the durable push coordinator (services/pushes.Coordinator), told about this replica's edge streams and the edges' reload reports.

Jump to

Keyboard shortcuts

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