This document covers advanced gRPC-Go features including compression, encoding, keepalive, backoff, connection management, and other advanced topics.
import "google.golang.org/grpc/encoding/gzip"
// gzip compression is built-in and automatically registered
// No explicit import needed for basic usageimport "google.golang.org/grpc"
// Client: request compression
conn, err := grpc.NewClient("localhost:50051",
grpc.WithDefaultCallOptions(grpc.UseCompressor("gzip")),
grpc.WithTransportCredentials(creds))
// Server: enable compression
server := grpc.NewServer()
// Per-call compression
ctx := context.Background()
resp, err := client.MyMethod(ctx, req, grpc.UseCompressor("gzip"))import (
"context"
"google.golang.org/grpc"
)
// Set compressor for response
func (s *server) MyMethod(ctx context.Context, req *pb.Request) (*pb.Response, error) {
// Set send compressor
grpc.SetSendCompressor(ctx, "gzip")
// Check client-supported compressors
compressors, err := grpc.ClientSupportedCompressors(ctx)
if err == nil {
log.Printf("Client supports: %v", compressors)
}
return &pb.Response{}, nil
}import "google.golang.org/grpc/encoding"
type myCompressor struct{}
func (c *myCompressor) Compress(w io.Writer) (io.WriteCloser, error) {
// Return compressed writer
return nil, nil
}
func (c *myCompressor) Decompress(r io.Reader) (io.Reader, error) {
// Return decompressed reader
return nil, nil
}
func (c *myCompressor) Name() string {
return "mycompressor"
}
// Register compressor
func init() {
encoding.RegisterCompressor(&myCompressor{})
}import "google.golang.org/grpc/encoding"
type myCodec struct{}
func (c *myCodec) Marshal(v any) ([]byte, error) {
// Custom marshaling
return nil, nil
}
func (c *myCodec) Unmarshal(data []byte, v any) error {
// Custom unmarshaling
return nil
}
func (c *myCodec) Name() string {
return "mycodec"
}
// Register codec
func init() {
encoding.RegisterCodec(&myCodec{})
}
// Use custom codec
conn, err := grpc.NewClient("localhost:50051",
grpc.WithDefaultCallOptions(grpc.CallContentSubtype("mycodec")),
grpc.WithTransportCredentials(creds))import (
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/keepalive"
)
kacp := keepalive.ClientParameters{
Time: 10 * time.Second, // Send pings every 10s if no activity
Timeout: 3 * time.Second, // Wait 3s for ping ack before considering connection dead
PermitWithoutStream: true, // Send pings even without active streams
}
conn, err := grpc.NewClient("localhost:50051",
grpc.WithKeepaliveParams(kacp),
grpc.WithTransportCredentials(creds))import (
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/keepalive"
)
kaep := keepalive.EnforcementPolicy{
MinTime: 5 * time.Second, // Min time client should wait between pings
PermitWithoutStream: true, // Allow pings even without active streams
}
kasp := keepalive.ServerParameters{
Time: 10 * time.Second, // Ping client if no activity for 10s
Timeout: 3 * time.Second, // Wait 3s for ping ack
}
server := grpc.NewServer(
grpc.KeepaliveEnforcementPolicy(kaep),
grpc.KeepaliveParams(kasp))import (
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/backoff"
)
backoffConfig := backoff.Config{
BaseDelay: 1.0 * time.Second, // Initial backoff
Multiplier: 1.6, // Backoff multiplier
Jitter: 0.2, // Jitter factor
MaxDelay: 120 * time.Second, // Max backoff
}
conn, err := grpc.NewClient("localhost:50051",
grpc.WithConnectParams(grpc.ConnectParams{
Backoff: backoffConfig,
}),
grpc.WithTransportCredentials(creds))conn, err := grpc.NewClient("localhost:50051",
grpc.WithConnectParams(grpc.ConnectParams{
MinConnectTimeout: 5 * time.Second,
}),
grpc.WithTransportCredentials(creds))import (
"time"
"google.golang.org/grpc"
)
// Experimental: Close idle connections after timeout
conn, err := grpc.NewClient("localhost:50051",
grpc.WithIdleTimeout(5 * time.Minute),
grpc.WithTransportCredentials(creds))// Get connection state
state := conn.GetState()
// Wait for state change
conn.WaitForStateChange(ctx, state)
// Trigger connection attempt (experimental)
conn.Connect()
// Reset connection backoff (experimental)
conn.ResetConnectBackoff()import "google.golang.org/grpc"
conn, err := grpc.NewClient("localhost:50051",
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(10 * 1024 * 1024), // 10 MB
grpc.MaxCallSendMsgSize(10 * 1024 * 1024), // 10 MB
),
grpc.WithTransportCredentials(creds))import "google.golang.org/grpc"
server := grpc.NewServer(
grpc.MaxRecvMsgSize(10 * 1024 * 1024), // 10 MB
grpc.MaxSendMsgSize(10 * 1024 * 1024)) // 10 MBimport "google.golang.org/grpc"
// Client
conn, err := grpc.NewClient("localhost:50051",
grpc.WithInitialWindowSize(65535),
grpc.WithInitialConnWindowSize(65535 * 16),
grpc.WithTransportCredentials(creds))
// Server
server := grpc.NewServer(
grpc.InitialWindowSize(65535),
grpc.InitialConnWindowSize(65535 * 16))import "google.golang.org/grpc"
// Client
conn, err := grpc.NewClient("localhost:50051",
grpc.WithReadBufferSize(32 * 1024),
grpc.WithWriteBufferSize(32 * 1024),
grpc.WithTransportCredentials(creds))
// Server
server := grpc.NewServer(
grpc.ReadBufferSize(32 * 1024),
grpc.WriteBufferSize(32 * 1024))import "google.golang.org/grpc"
server := grpc.NewServer(
grpc.MaxConcurrentStreams(100))import "google.golang.org/grpc"
// Client
conn, err := grpc.NewClient("localhost:50051",
grpc.WithMaxHeaderListSize(16 * 1024),
grpc.WithTransportCredentials(creds))
// Server
server := grpc.NewServer(
grpc.MaxHeaderListSize(16 * 1024))import (
"context"
"net"
"time"
"google.golang.org/grpc"
)
customDialer := func(ctx context.Context, addr string) (net.Conn, error) {
// Custom dialing logic
d := net.Dialer{Timeout: 5 * time.Second}
return d.DialContext(ctx, "tcp", addr)
}
conn, err := grpc.NewClient("localhost:50051",
grpc.WithContextDialer(customDialer),
grpc.WithTransportCredentials(insecure.NewCredentials()))The tap package allows intercepting connections before RPC processing.
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/tap"
)
tapHandle := func(ctx context.Context, info *tap.Info) (context.Context, error) {
// Check request before creating stream
// Can reject connection by returning error
if !isAllowed(info.FullMethodName) {
return nil, status.Error(codes.PermissionDenied, "method not allowed")
}
return ctx, nil
}
server := grpc.NewServer(
grpc.InTapHandle(tapHandle))import "google.golang.org/grpc"
// Override authority for specific call
resp, err := client.MyMethod(ctx, req,
grpc.CallAuthority("custom-authority.example.com"))
// Set default authority for connection
conn, err := grpc.NewClient("localhost:50051",
grpc.WithAuthority("custom-authority.example.com"),
grpc.WithTransportCredentials(creds))import "google.golang.org/grpc"
// Wait for connection to be ready before sending RPC
resp, err := client.MyMethod(ctx, req, grpc.WaitForReady(true))
// Fail immediately if not connected
resp, err := client.MyMethod(ctx, req, grpc.WaitForReady(false))