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
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