Dial a service with middleware¶
grpcclient.Dial builds the connection and selects credentials; the per-call
behaviour — circuit breaking, OpenTelemetry — comes from
go/transit's gRPC client interceptors, which
you pass to Dial as ordinary grpc.DialOptions.
import (
"gitlab.com/phpboyscout/go/grpcclient"
transitgrpc "gitlab.com/phpboyscout/go/transit/grpc"
"google.golang.org/grpc"
)
The client-side interceptors¶
go/transit/grpc exposes three client-side helpers:
| Helper | Type | Wire it with |
|---|---|---|
CircuitBreakerInterceptor(log, cfg) |
grpc.UnaryClientInterceptor |
grpc.WithChainUnaryInterceptor(...) |
CircuitBreakerStreamInterceptor(log, cfg) |
grpc.StreamClientInterceptor |
grpc.WithChainStreamInterceptor(...) |
OTelClientHandler(opts...) |
grpc.DialOption |
pass directly to Dial |
(Request logging is a server-side interceptor in transit — there is no client logging interceptor.)
A full client stack¶
cfg := transitgrpc.DefaultCircuitBreakerConfig()
conn, err := grpcclient.Dial(
grpcclient.Target{Host: "svc.internal", Port: 443, TLS: pair},
// circuit breaking on both unary and streaming calls
grpc.WithChainUnaryInterceptor(transitgrpc.CircuitBreakerInterceptor(log, cfg)),
grpc.WithChainStreamInterceptor(transitgrpc.CircuitBreakerStreamInterceptor(log, cfg)),
// OpenTelemetry client instrumentation
transitgrpc.OTelClientHandler(),
)
if err != nil {
return err
}
defer conn.Close()
Because Dial appends your options after the transport credentials it sets from
Target.TLS, the credentials always win — a caller cannot accidentally weaken the
target's transport security through an option.
Credentials come from the Target¶
You never pass grpc.WithTransportCredentials yourself: Dial derives it from
Target.TLS. Set TLS.Enabled and (optionally) TLS.Cert to control it — see
The Target model & credentials.
Bring your own dial options¶
Any grpc.DialOption is accepted — keepalive, message-size limits, a custom resolver,
a service-config — and applied on top of the credentials Dial sets: