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:
- Codec returns a hybrid google.golang.org/grpc/encoding.CodecV2 that passes relayed frames through as raw bytes and delegates every other message to the standard proto codec, so locally registered services (such as health) keep working alongside the relay.
- Handler returns a google.golang.org/grpc.StreamHandler for use as a google.golang.org/grpc.UnknownServiceHandler. It opens a same-method stream on the upstream connection and pumps raw frames in both directions, propagating header, trailer, and status verbatim.
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 ¶
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
func PeekInterceptor(r Reflector, a services.Allowlist) grpc.StreamServerInterceptor
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
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 ¶
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 ¶
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 )
type Reflector ¶
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 ¶
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 ¶
Decision increments the decision counter for the chosen upstream and outcome.
func (*Reporter) ForwardingError ¶
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.