controlclient

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: May 31, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package controlclient is the convenience layer subservices use to self-register with a gwag control plane: one Register call, a background heartbeat goroutine, and graceful Deregister on Close.

//go:embed greeter.proto
var greeterProto []byte

reg, err := controlclient.SelfRegister(ctx, controlclient.Options{
    GatewayAddr: "gateway:50090",
    ServiceAddr: "greeter:50051",
    Services: []controlclient.Service{
        {Namespace: "greeter", ProtoSource: greeterProto},
    },
})
if err != nil { log.Fatal(err) }
defer reg.Close(context.Background())

Holds an open *grpc.ClientConn to the gateway for the lifetime of the registration. Re-Register is automatic on heartbeat-not-ok (gateway evicted us, e.g. after a restart) — the goroutine fires a fresh Register and resumes.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Options

type Options struct {
	// GatewayAddr is the gRPC host:port where the gateway's control
	// plane is listening (the WithControlPlane addr).
	GatewayAddr string

	// ServiceAddr is the host:port where this service's gRPC server
	// is reachable. Passed to the gateway verbatim.
	ServiceAddr string

	// Services to register. All bind to ServiceAddr. Empty rejected.
	Services []Service

	// InstanceID is echoed in ListRegistrations for operator debugging.
	// Free-form ("greeter@pod-abc"). Optional.
	InstanceID string

	// TTL is how long the gateway should retain the registration
	// without seeing a heartbeat. 0 → server default (30s).
	TTL time.Duration

	// HeartbeatInterval defaults to TTL/3 (or 10s if TTL is 0).
	HeartbeatInterval time.Duration

	// DialOptions are appended to the gateway-conn dial. Insecure is
	// the default if none are supplied.
	DialOptions []grpc.DialOption

	// Logger is called with non-fatal events (eviction recovery,
	// heartbeat errors). Defaults to log.Printf-equivalent.
	Logger func(format string, args ...any)

	// BuildTag, when non-empty, marks the calling binary as a release
	// build. SelfRegister refuses any Service whose Version is
	// "unstable" — release artifacts belong to numbered cuts (vN), not
	// trunk's mutable slot. Plan §4 forcing function: a redeployed
	// v3-era pod can't accidentally overwrite `unstable` because its
	// release binary still carries v3's tag.
	//
	// Recommended pattern: stamp via -ldflags "-X 'main.buildTag=v1.2.3'"
	// (or whatever the project's release machinery emits) and pass it
	// through to controlclient.Options. Trunk CI omits it; release CI
	// sets it. Empty defeats the lint, so don't paper over a CI bug
	// by clearing the field — unset means "trunk", set means "release".
	BuildTag string
}

Options configures a SelfRegister call. GatewayAddr, ServiceAddr, and at least one Service entry are required.

Stability: stable

type Registration

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

Registration is the live handle returned by SelfRegister. Close stops the heartbeat goroutine and gracefully deregisters.

Stability: stable

func SelfRegister

func SelfRegister(ctx context.Context, opts Options) (*Registration, error)

SelfRegister registers with the gateway control plane and starts a background heartbeat goroutine. Returns a Registration; call Close when the service shuts down to deregister and stop the goroutine. Blocks until the initial Register RPC succeeds or ctx is cancelled.

Stability: stable

func (*Registration) Close

func (r *Registration) Close(ctx context.Context) error

Close stops the heartbeat and gracefully deregisters. Safe to call once. ctx is used only for the Deregister call.

Stability: stable

type Service

type Service struct {
	// Namespace under which to mount this service in the gateway's
	// GraphQL surface. Empty falls back to the proto's filename stem
	// (proto bindings) or the OpenAPI spec's Info.Title (OpenAPI
	// bindings).
	Namespace string

	// Version, e.g. "v1", "v2". Multiple versions of the same namespace
	// coexist on the gateway; latest surfaces flat under the namespace,
	// older versions appear as `vN` sub-objects with @deprecated.
	// Empty defaults to "v1". Ignored for OpenAPI bindings (single
	// version per ns in v1).
	Version string

	// ProtoSource is the raw bytes of the entrypoint .proto file —
	// exactly what the operator wrote on disk. The receiving gateway
	// compiles via protocompile (SourceInfoStandard) so leading /
	// trailing comments survive into the GraphQL SDL and MCP search
	// corpus. Most callers `//go:embed greeter.proto` and pass the
	// embedded bytes here.
	//
	// Mutually exclusive with ProtoFS, OpenAPISpec, GraphQLEndpoint.
	ProtoSource []byte

	// ProtoImports passes transitive .proto imports keyed by their
	// import path (e.g. "auth.proto"). Required only when ProtoSource
	// has `import "..."` statements; well-known imports
	// (google/protobuf/*) resolve automatically. Single-file .protos
	// leave this nil.
	ProtoImports map[string][]byte

	// ProtoFS is the multi-file ergonomic shape: pass any fs.FS
	// (embed.FS, os.DirFS(...), tar/zip wrappers, anything that
	// satisfies the interface) and the controlclient walks it to
	// build ProtoSource (= bytes of ProtoEntry) and ProtoImports
	// (= every other .proto under the FS, keyed by relative path).
	// Use this when the service has many .proto files; use
	// ProtoSource directly for single-file services.
	//
	// Mutually exclusive with ProtoSource / ProtoImports.
	ProtoFS fs.FS

	// ProtoEntry is the entrypoint filename within ProtoFS (e.g.
	// "user.proto"). Required when ProtoFS is set.
	ProtoEntry string

	// OpenAPISpec is the raw bytes of an OpenAPI 3.x document (JSON
	// or YAML; kin-openapi parses either). When set, ServiceAddr in
	// the parent Options is the HTTP base URL the gateway dispatches
	// to (e.g. "https://billing.internal").
	OpenAPISpec []byte

	// GraphQLEndpoint is the URL of an upstream GraphQL service to
	// ingest under this Namespace. Mutually exclusive with the proto
	// source fields and OpenAPISpec. The receiving gateway runs the
	// canonical introspection query against this endpoint at Register
	// time and forwards dispatches back to it. ServiceAddr is ignored
	// for GraphQL bindings — the endpoint URL carries both the
	// schema source and the dispatch destination.
	GraphQLEndpoint string

	// MaxConcurrency caps simultaneous unary dispatches against this
	// (namespace, version) on the receiving gateway. Overrides the
	// gateway-wide BackpressureOptions.MaxInflight default for this
	// one binding. 0 → fall back to the gateway default.
	MaxConcurrency uint32

	// MaxConcurrencyPerInstance caps simultaneous unary dispatches
	// against any single replica behind this binding. New axis: the
	// service-level cap above bounds the pool, this bounds each
	// replica individually. 0 → unbounded per replica (only the
	// service-level cap applies).
	MaxConcurrencyPerInstance uint32
}

Service describes one service binding to register with the gateway. At least one of ProtoSource/ProtoFS, OpenAPISpec, or GraphQLEndpoint must be set. Multiple Services can be passed in a single SelfRegister call to bind multiple namespaces in one go.

Stability: stable

Jump to

Keyboard shortcuts

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