router

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Aug 13, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package router transparently forwards inbound gRPC traffic to an upstream connection without decoding it.

It provides two pieces that are wired onto the inbound server:

Together they let the server forward any method it does not handle locally, with no knowledge of the underlying protobuf messages, selecting the upstream connection per request from the routing table CompileMux compiles.

internal/dataplane assembles these pieces directly: it calls CompileMux, Codec, NewDirector, NewReporter, and Handler to build the request path.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Codec

func Codec() encoding.CodecV2

Codec returns the hybrid pass-through codec. It must be applied per-call via grpc.ForceServerCodecV2 / grpc.ForceCodecV2; it is deliberately not registered globally so it never shadows the real proto codec process-wide.

func Handler

Handler returns a grpc.StreamHandler suitable for grpc.UnknownServiceHandler, reporting a stream_setup forwarding error via rep when opening the upstream stream fails. A method whose service a does not allow is rejected with Unimplemented before any upstream work, so the proxy answers as a server that does not implement it rather than revealing that an upstream might. It reads the request namespace from the meta.Target that PeekInterceptor resolved, asks d for the upstream connection, then transparently forwards the stream to that upstream using the same full method name: it replays the first frame, pumps raw frames in both directions, and propagates header, trailer, and status verbatim.

func PeekInterceptor added in v0.5.0

PeekInterceptor returns a stream server interceptor that resolves the stream's meta.Target before any later stage runs, so authentication and routing decide on the same view of the request. Every stream gets the method it named. For a service a forwards, it also buffers the first client frame, reads the namespace out of it with r, and hands the handler a stream that replays that frame; for any other service it leaves the stream untouched, so whatever serves it reads its own first message.

Install it ahead of anything that reads the Target, and note that it is what makes Handler usable at all: the handler refuses a stream this never saw.

Types

type Director

type Director interface {
	Resolve(ctx context.Context, method, namespace string, md map[string][]string) (Target, error)
}

Director selects the upstream for a request. Resolve receives the full method, the namespace peeked from the first request message (empty when the client sent no message), and the incoming metadata, and returns the Target to forward over. A non-nil error aborts the stream and is returned to the caller verbatim, so implementations should return a gRPC status error.

func NewDirector added in v0.5.0

func NewDirector(
	mux *Mux,
	conns map[string]grpc.ClientConnInterface,
	rep *Reporter,
	log logger.Logger,
) Director

NewDirector returns the Director that routes a request with mux and looks the chosen upstream up in conns. A nil log falls back to the default logger.

type Mux

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

Mux selects the upstream that serves a request by matching it against an ordered list of rules. It holds upstream names only, not connections, so callers map the name Switch returns to a connection. A Mux is read-only after construction and safe for concurrent use.

func CompileMux added in v0.5.0

func CompileMux(r config.Routing) (*Mux, error)

CompileMux compiles routing configuration into a Mux. An empty rule namespace matches every namespace, and metadata keys are lowercased to match canonical gRPC metadata.

func New

func New(defUpstream, sysUpstream string, rules ...Rule) *Mux

New returns a Mux that evaluates rules in order. defUpstream is returned when no rule matches; sysUpstream, when non-empty, serves a request that carries no namespace and matches no rule. Either name may be empty, in which case Switch can return "" to signal that the request is unroutable.

func (*Mux) Switch

func (m *Mux) Switch(ns string, md map[string][]string) (string, Outcome)

Switch returns the upstream that serves a request with the given namespace and metadata, and the Outcome describing why it was chosen. Rules are evaluated in order and the first match wins. With no matching rule, a request with no namespace goes to the system upstream if configured, and every other request goes to the default upstream. An empty result (the selected upstream is unset) is reported as OutcomeUnroutable and the caller treats the request as unroutable.

type Outcome

type Outcome byte

Outcome describes why Switch chose (or failed to choose) an upstream.

const (
	// OutcomeMatch means a rule matched the request.
	OutcomeMatch Outcome = iota
	// OutcomeDefault means the request fell through to the default upstream.
	OutcomeDefault
	// OutcomeSystem means a no-namespace request went to the system upstream.
	OutcomeSystem
	// OutcomeUnroutable means no upstream was selected (result "").
	OutcomeUnroutable
)

func (Outcome) String

func (o Outcome) String() string

String returns the metric label value for the outcome.

type Reflector

type Reflector interface {
	Namespace(string, []byte) string
}

Reflector extracts the Temporal namespace from a request. Namespace receives the full method and the raw bytes of the first request message and returns the namespace, or "" when it cannot determine one.

type Reporter

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

Reporter records router telemetry to Prometheus: routing decisions and the forwarding failures the router itself originates. It pre-resolves a counter for every meaningful (upstream, outcome) and (upstream, reason) combination so the emit path is a lock-free map read; an unexpected label combination falls back to CounterVec.WithLabelValues. A Reporter is safe for concurrent use.

func NewReporter

func NewReporter(f *metrics.Factory, upstreams []string) *Reporter

NewReporter builds the Prometheus-backed Reporter, registering its collectors with the factory's registry and pre-resolving the meaningful label combinations so every series starts at zero. upstreams is the configured upstream name list.

func (*Reporter) Decision

func (r *Reporter) Decision(upstream string, outcome Outcome)

Decision increments the decision counter for the chosen upstream and outcome.

func (*Reporter) ForwardingError

func (r *Reporter) ForwardingError(upstream, reason string)

ForwardingError increments the forwarding-error counter for the upstream and reason.

type Rule

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

Rule routes every request it matches to a named upstream. A request matches when the rule's namespace matcher accepts the request namespace and, for every constrained metadata key, at least one of the request's values for that key is accepted. Metadata keys are compared as stored, so the rule builder is responsible for canonicalizing them (gRPC lowercases metadata keys). Construct rules with CompileMux.

type Target

type Target struct {
	Upstream string
	Conn     grpc.ClientConnInterface
}

Target is the routing result returned by Director.Resolve on success: the chosen upstream's name (always non-empty) and the connection to forward the stream over. On a non-nil error the Target is unused and callers must ignore its fields.

Jump to

Keyboard shortcuts

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