Skip to content

Latest commit

 

History

History

grpcserver

gRPC Server Module

ci go report codecov Deps PkgGoDev

gRPC server module based on gRPC-Go.

Installation

go get github.com/ankorstore/yokai/grpcserver

Documentation

Usage

This module provides a GrpcServerFactory, allowing to build an grpc.Server instance.

package main

import (
	"github.com/ankorstore/yokai/grpcserver"
	"google.golang.org/grpc"
)

var server, _ = grpcserver.NewDefaultGrpcServerFactory().Create()

// equivalent to:
var server, _ = grpcserver.NewDefaultGrpcServerFactory().Create(
	grpcserver.WithServerOptions([]grpc.ServerOption{}), // no specific server options by default 
	grpcserver.WithReflection(false),                    // reflection disabled by default
)

See gRPC-Go documentation for more details.

Add-ons

This module provides several add-ons ready to use to enrich your gRPC server.

Reflection

This module provides the possibility to easily enable gRPC server reflection, disabled by default:

package main

import (
	"github.com/ankorstore/yokai/grpcserver"
)

func main() {
	server, _ := grpcserver.NewDefaultGrpcServerFactory().Create(
		grpcserver.WithReflection(true),
	)
}

Reflection usage is helpful for developing or testing your gRPC services, but it is not recommended for production usage.

Panic recovery

This module provides an GrpcPanicRecoveryHandler, compatible with the recovery interceptor, to automatically recover from panics in your gRPC services:

package main

import (
	"github.com/ankorstore/yokai/grpcserver"
	"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery"
	"google.golang.org/grpc"
)

func main() {
	handler := grpcserver.NewGrpcPanicRecoveryHandler()

	server, _ := grpcserver.NewDefaultGrpcServerFactory().Create(
		grpcserver.WithServerOptions(
			grpc.UnaryInterceptor(recovery.UnaryServerInterceptor(recovery.WithRecoveryHandlerContext(handler.Handle(false)))),
			grpc.StreamInterceptor(recovery.StreamServerInterceptor(recovery.WithRecoveryHandlerContext(handler.Handle(false)))),
		),
	)
}

You can also use Handle(true) to append on the handler gRPC response and logs more information about the panic and the debug stack ( not suitable for production).

Logger interceptor

This module provides a GrpcLoggerInterceptor to automatically log unary and streaming RPCs calls (status, type, duration, etc.), compatible with the log module.

Using this interceptor will also provide a logger instance in the context, that you can retrieve with the CtxLogger method to produce correlated logs from your gRPC services.

package main

import (
	"github.com/ankorstore/yokai/generate/uuid"
	"github.com/ankorstore/yokai/grpcserver"
	"github.com/ankorstore/yokai/log"
	"google.golang.org/grpc"
)

func main() {
	logger, _ := log.NewDefaultLoggerFactory().Create()

	loggerInterceptor := grpcserver.NewGrpcLoggerInterceptor(uuid.NewDefaultUuidGenerator, logger)

	server, _ := grpcserver.NewDefaultGrpcServerFactory().Create(
		grpcserver.WithServerOptions(
			grpc.UnaryInterceptor(loggerInterceptor.UnaryInterceptor()),
			grpc.StreamInterceptor(loggerInterceptor.StreamInterceptor()),
		),
	)
}

The interceptor will automatically enrich each log records with the x-request-id fetch from the context metadata in the field requestID.

You can specify additional metadata to add to logs records:

  • the key is the metadata name to fetch
  • the value is the log field to fill
loggerInterceptor.Metadata(
    map[string]string{
        "x-some-metadata": "someMetadata",
        "x-other-metadata": "otherMetadata",
    },
)

You can also specify a list of gRPC methods to exclude from logging:

loggerInterceptor.Exlude("/test.Service/Unary", "/test.Service/Bidi")

Note: even if excluded, failing gRPC methods calls will still be logged for observability purposes.

Healthcheck service

This module provides a GrpcHealthCheckService, compatible with the healthcheck module:

package main

import (
	"probes"

	"github.com/ankorstore/yokai/grpcserver"
	"github.com/ankorstore/yokai/healthcheck"
	"google.golang.org/grpc/health/grpc_health_v1"
)

func main() {
	checker, _ := healthcheck.NewDefaultCheckerFactory().Create(
		healthcheck.WithProbe(probes.SomeProbe()),                            // register for startup, liveness and readiness
		healthcheck.WithProbe(probes.SomeOtherProbe(), healthcheck.Liveness), // register for liveness only
	)

	server, _ := grpcserver.NewDefaultGrpcServerFactory().Create()

	grpc_health_v1.RegisterHealthServer(server, grpcserver.NewGrpcHealthCheckService(checker))
}

This will expose the Check and Watch RPCs, suitable for k8s startup, readiness or liveness probes.

The checker will:

  • run the liveness probes checks if the request service name contains liveness (like kubernetes::liveness)
  • or run the readiness probes checks if the request service name contains readiness (like kubernetes::readiness)
  • or run the startup probes checks otherwise