Documentation
¶
Index ¶
- Constants
- func CircuitBreakerInterceptor(log *slog.Logger, cfg CircuitBreakerConfig) grpc.UnaryClientInterceptor
- func CircuitBreakerStreamInterceptor(log *slog.Logger, cfg CircuitBreakerConfig) grpc.StreamClientInterceptor
- func OTelClientHandler(opts ...otelgrpc.Option) grpc.DialOption
- func OTelStatsHandler(opts ...otelgrpc.Option) grpc.ServerOption
- func PeerKey(ctx context.Context, _ string) string
- type CircuitBreakerConfig
- type CircuitBreakerConfigOverrides
- type CircuitState
- type GRPCLoggingOption
- type Interceptor
- type InterceptorChain
- type RateLimitConfig
- type RateLimitConfigOverrides
Constants ¶
const ( // StateClosed admits all RPCs; failures are counted. StateClosed = CircuitState(resilience.StateClosed) // StateOpen rejects all RPCs immediately with codes.Unavailable until the // cooldown elapses, then transitions to StateHalfOpen. StateOpen = CircuitState(resilience.StateOpen) // StateHalfOpen admits a limited number of trial RPCs; success closes the // breaker, failure re-opens it. StateHalfOpen = CircuitState(resilience.StateHalfOpen) )
The public states are derived from the shared core so the two enumerations can never silently drift out of order.
Variables ¶
This section is empty.
Functions ¶
func CircuitBreakerInterceptor ¶
func CircuitBreakerInterceptor(log *slog.Logger, cfg CircuitBreakerConfig) grpc.UnaryClientInterceptor
CircuitBreakerInterceptor returns a unary client interceptor that opens when a downstream is consistently failing and rejects calls with codes.Unavailable while open, avoiding wasted calls against a service known to be down. Install it via grpc.WithChainUnaryInterceptor.
func CircuitBreakerStreamInterceptor ¶
func CircuitBreakerStreamInterceptor(log *slog.Logger, cfg CircuitBreakerConfig) grpc.StreamClientInterceptor
CircuitBreakerStreamInterceptor returns a stream client interceptor with the same breaker semantics. Successful stream ESTABLISHMENT is the breaker verdict for the call (in HalfOpen it is the trial verdict, releasing the trial slot immediately) — a long-lived or abandoned stream therefore never holds the half-open trial slot for its lifetime. The ClientStream is still wrapped so per-message errors (a RecvMsg/SendMsg that returns a classified failure) count against the breaker's Closed-state failure threshold and can re-trip it; a clean io.EOF reports nothing further.
func OTelClientHandler ¶
func OTelClientHandler(opts ...otelgrpc.Option) grpc.DialOption
OTelClientHandler returns a grpc.DialOption that instruments a client connection with OpenTelemetry: a client span per RPC, and — using the global propagator — the trace context injected into the outgoing metadata, so a downstream gRPC server continues the same trace rather than starting a new one. It reads the globally-installed providers (see telemetry.Setup) and is a noop until those are installed. The gateway applies it by default, so a REST request and the gRPC call it proxies land in one trace.
func OTelStatsHandler ¶
func OTelStatsHandler(opts ...otelgrpc.Option) grpc.ServerOption
OTelStatsHandler returns a grpc.ServerOption that installs OpenTelemetry instrumentation for every RPC — server spans and the standard server metrics (rpc.server.*) — reading whichever TracerProvider and MeterProvider are installed as the OTel globals (see telemetry.Setup). It is a stats handler rather than an interceptor because that is the instrumentation the OTel gRPC contrib library ships and the shape the semantic conventions are defined against.
Pass it to Register alongside any other server options:
grpc.RegisterFromContainable(ctx, "grpc", controller, cfg, log, grpc.OTelStatsHandler())
Types ¶
type CircuitBreakerConfig ¶
type CircuitBreakerConfig struct {
// FailureThreshold is the number of consecutive failures (in Closed) that
// trips the breaker open. Must be >= 1. Default: 5.
FailureThreshold int `mapstructure:"failure_threshold" yaml:"failure_threshold" json:"failure_threshold"`
// Cooldown is how long the breaker stays Open before a trial. Default: 30s.
Cooldown time.Duration `mapstructure:"cooldown" yaml:"cooldown" json:"cooldown"`
// HalfOpenMaxRequests is the number of trial RPCs allowed in HalfOpen.
// Must be >= 1. Default: 1.
HalfOpenMaxRequests int `mapstructure:"half_open_max_requests" yaml:"half_open_max_requests" json:"half_open_max_requests"`
// IsFailure classifies an RPC outcome. When nil, the default treats
// Unavailable and DeadlineExceeded as failures and every other code
// (including OK and ResourceExhausted) as a success.
//
// ResourceExhausted is deliberately NOT a failure: like an HTTP 429 it means
// "you are being rate-limited", which is the retry/backoff layer's concern,
// not a signal that the downstream is unhealthy. Counting it would let a
// server's own rate limiter trip its callers' breakers. Supply a custom
// IsFailure to change this.
IsFailure func(err error) bool `mapstructure:"-" yaml:"-" json:"-"`
// OnStateChange is invoked on every state transition. Optional; transitions
// are also logged via the constructor's logger.
OnStateChange func(from, to CircuitState) `mapstructure:"-" yaml:"-" json:"-"`
}
CircuitBreakerConfig configures the client-side circuit breaker for gRPC.
func DefaultCircuitBreakerConfig ¶
func DefaultCircuitBreakerConfig() CircuitBreakerConfig
DefaultCircuitBreakerConfig returns: threshold 5, cooldown 30s, half-open trial 1, default Unavailable/DeadlineExceeded failure classification.
func MergeCircuitBreakerConfig ¶
func MergeCircuitBreakerConfig(base, override CircuitBreakerConfig, fields CircuitBreakerConfigOverrides) CircuitBreakerConfig
MergeCircuitBreakerConfig applies explicitly supplied typed override values to base while leaving code-only function fields under caller control.
type CircuitBreakerConfigOverrides ¶
type CircuitBreakerConfigOverrides struct {
FailureThreshold bool
Cooldown bool
HalfOpenMaxRequests bool
}
CircuitBreakerConfigOverrides records which typed circuit breaker config fields were explicitly supplied by an adapter.
type CircuitState ¶
type CircuitState int
CircuitState is the client circuit breaker's state.
func (CircuitState) String ¶
func (s CircuitState) String() string
String renders the state for logging.
type GRPCLoggingOption ¶
type GRPCLoggingOption func(*grpcLoggingConfig)
GRPCLoggingOption configures gRPC transport logging behaviour.
func WithGRPCLogLevel ¶
func WithGRPCLogLevel(level slog.Level) GRPCLoggingOption
WithGRPCLogLevel sets the log level for successful RPCs. Errors always log at slog.LevelError.
func WithGRPCPathFilter ¶
func WithGRPCPathFilter(methods ...string) GRPCLoggingOption
WithGRPCPathFilter excludes RPCs matching the given full method names from logging.
func WithoutGRPCLatency ¶
func WithoutGRPCLatency() GRPCLoggingOption
WithoutGRPCLatency disables the "latency" field.
type Interceptor ¶
type Interceptor struct {
Unary grpc.UnaryServerInterceptor
Stream grpc.StreamServerInterceptor
}
Interceptor groups a paired unary and stream interceptor. Either field may be nil if the interceptor only applies to one RPC type.
func LoggingInterceptor ¶
func LoggingInterceptor(l *slog.Logger, opts ...GRPCLoggingOption) Interceptor
LoggingInterceptor returns an Interceptor (unary + stream) that logs each completed RPC.
func RateLimitInterceptor ¶
func RateLimitInterceptor(log *slog.Logger, cfg RateLimitConfig) Interceptor
RateLimitInterceptor returns an Interceptor (unary + stream) that admits RPCs under a token-bucket limiter and rejects excess with codes.ResourceExhausted. It composes into any InterceptorChain. Per-method or per-client scoping is achieved by setting KeyFunc (e.g. PeerKey, or a func keying on fullMethod).
Like the HTTP limiter, admission is non-blocking (Allow, not Wait): ingress must reject excess, never queue it, or a flood would exhaust memory.
type InterceptorChain ¶
type InterceptorChain struct {
// contains filtered or unexported fields
}
InterceptorChain composes zero or more gRPC interceptors into ordered slices suitable for grpc.ChainUnaryInterceptor and grpc.ChainStreamInterceptor.
func NewInterceptorChain ¶
func NewInterceptorChain(interceptors ...Interceptor) InterceptorChain
NewInterceptorChain creates a new interceptor chain. Each Interceptor argument provides a unary interceptor, a stream interceptor, or both. Nil entries in either field are silently skipped.
func (InterceptorChain) Append ¶
func (c InterceptorChain) Append(interceptors ...Interceptor) InterceptorChain
Append returns a new InterceptorChain with additional interceptors appended. The original chain is not modified.
func (InterceptorChain) ServerOptions ¶
func (c InterceptorChain) ServerOptions() []grpc.ServerOption
ServerOptions returns grpc.ServerOption values that install the chain. This is the primary integration point — pass the result to grpc.NewServer or to NewServer's variadic options.
chain := NewInterceptorChain(logging, recovery) srv, _ := NewServerFromContainable(cfg, chain.ServerOptions()...)
type RateLimitConfig ¶
type RateLimitConfig struct {
// RequestsPerSecond is the sustained fill rate. Must be > 0. Default: 50.
RequestsPerSecond float64 `mapstructure:"requests_per_second" yaml:"requests_per_second" json:"requests_per_second"`
// Burst is the bucket capacity. Must be >= 1. Default: 100.
Burst int `mapstructure:"burst" yaml:"burst" json:"burst"`
// MaxTrackedKeys bounds the per-key bucket store (ignored when KeyFunc is
// nil). Must be >= 1. Default: 8192.
MaxTrackedKeys int `mapstructure:"max_tracked_keys" yaml:"max_tracked_keys" json:"max_tracked_keys"`
// KeyFunc derives the limiter key from the RPC context and full method name,
// enabling per-client or per-method limiting. When nil, a single global
// bucket is used. See PeerKey.
KeyFunc func(ctx context.Context, fullMethod string) string `mapstructure:"-" yaml:"-" json:"-"`
// OnLimited is invoked when an RPC is rejected. Optional.
OnLimited func(ctx context.Context, fullMethod string) `mapstructure:"-" yaml:"-" json:"-"`
}
RateLimitConfig configures the server-side token-bucket rate limiter for gRPC ingress, mirroring the HTTP server limiter.
func DefaultRateLimitConfig ¶
func DefaultRateLimitConfig() RateLimitConfig
DefaultRateLimitConfig returns a limiter suitable for a modest management server: 50 rps sustained, burst 100, single global bucket.
func MergeRateLimitConfig ¶
func MergeRateLimitConfig(base, override RateLimitConfig, fields RateLimitConfigOverrides) RateLimitConfig
MergeRateLimitConfig applies explicitly supplied typed override values to base while leaving code-only function fields under caller control.
type RateLimitConfigOverrides ¶
RateLimitConfigOverrides records which typed rate limit config fields were explicitly supplied by an adapter.