65 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			65 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
| package grpc
 | |
| 
 | |
| import (
 | |
| 	"time"
 | |
| 
 | |
| 	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
 | |
| 	"golang.org/x/net/context"
 | |
| 	"google.golang.org/grpc"
 | |
| 	"google.golang.org/grpc/metadata"
 | |
| 
 | |
| 	berrors "github.com/letsencrypt/boulder/errors"
 | |
| )
 | |
| 
 | |
| // serverInterceptor is a gRPC interceptor that adds Prometheus
 | |
| // metrics to requests handled by a gRPC server, and wraps Boulder-specific
 | |
| // errors for transmission in a grpc/metadata trailer (see bcodes.go).
 | |
| type serverInterceptor struct{}
 | |
| 
 | |
| func (si *serverInterceptor) intercept(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
 | |
| 	if info == nil {
 | |
| 		return nil, berrors.InternalServerError("passed nil *grpc.UnaryServerInfo")
 | |
| 	}
 | |
| 	resp, err := grpc_prometheus.UnaryServerInterceptor(ctx, req, info, handler)
 | |
| 	if err != nil {
 | |
| 		err = wrapError(ctx, err)
 | |
| 	}
 | |
| 	return resp, err
 | |
| }
 | |
| 
 | |
| // clientInterceptor is a gRPC interceptor that adds Prometheus
 | |
| // metrics to sent requests, and disables FailFast. We disable FailFast because
 | |
| // non-FailFast mode is most similar to the old AMQP RPC layer: If a client
 | |
| // makes a request while all backends are briefly down (e.g. for a restart), the
 | |
| // request doesn't necessarily fail. A backend can service the request if it
 | |
| // comes back up within the timeout. Under gRPC the same effect is achieved by
 | |
| // retries up to the Context deadline.
 | |
| type clientInterceptor struct {
 | |
| 	timeout time.Duration
 | |
| }
 | |
| 
 | |
| // intercept fulfils the grpc.UnaryClientInterceptor interface, it should be noted that while this API
 | |
| // is currently experimental the metrics it reports should be kept as stable as can be, *within reason*.
 | |
| func (ci *clientInterceptor) intercept(
 | |
| 	ctx context.Context,
 | |
| 	method string,
 | |
| 	req,
 | |
| 	reply interface{},
 | |
| 	cc *grpc.ClientConn,
 | |
| 	invoker grpc.UnaryInvoker,
 | |
| 	opts ...grpc.CallOption) error {
 | |
| 	localCtx, cancel := context.WithTimeout(ctx, ci.timeout)
 | |
| 	defer cancel()
 | |
| 	// Disable fail-fast so RPCs will retry until deadline, even if all backends
 | |
| 	// are down.
 | |
| 	opts = append(opts, grpc.FailFast(false))
 | |
| 	// Create grpc/metadata.Metadata to encode internal error type if one is returned
 | |
| 	md := metadata.New(nil)
 | |
| 	opts = append(opts, grpc.Trailer(&md))
 | |
| 	err := grpc_prometheus.UnaryClientInterceptor(localCtx, method, req, reply, cc, invoker, opts...)
 | |
| 	if err != nil {
 | |
| 		err = unwrapError(err, md)
 | |
| 	}
 | |
| 	return err
 | |
| }
 |