protoc-gen-go-grpc: add requirement of embedding UnimplementedServer in services (#3657)

This commit is contained in:
Doug Fawley 2020-06-04 10:56:13 -07:00 committed by GitHub
parent 42eed59dfa
commit ad51f572fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 120 additions and 24 deletions

View File

@ -61,12 +61,14 @@ func (x *loadBalancerBalanceLoadClient) Recv() (*LoadBalanceResponse, error) {
}
// LoadBalancerServer is the server API for LoadBalancer service.
// All implementations should embed UnimplementedLoadBalancerServer
// for forward compatibility
type LoadBalancerServer interface {
// Bidirectional rpc to get a list of servers.
BalanceLoad(LoadBalancer_BalanceLoadServer) error
}
// UnimplementedLoadBalancerServer can be embedded to have forward compatible implementations.
// UnimplementedLoadBalancerServer should be embedded to have forward compatible implementations.
type UnimplementedLoadBalancerServer struct {
}

View File

@ -187,6 +187,7 @@ func (s *rpcStats) String() string {
}
type remoteBalancer struct {
lbgrpc.UnimplementedLoadBalancerServer
sls chan *lbpb.ServerList
statsDura time.Duration
done chan struct{}

View File

@ -39,12 +39,14 @@ func (c *routeLookupServiceClient) RouteLookup(ctx context.Context, in *RouteLoo
}
// RouteLookupServiceServer is the server API for RouteLookupService service.
// All implementations should embed UnimplementedRouteLookupServiceServer
// for forward compatibility
type RouteLookupServiceServer interface {
// Lookup returns a target for a single key.
RouteLookup(context.Context, *RouteLookupRequest) (*RouteLookupResponse, error)
}
// UnimplementedRouteLookupServiceServer can be embedded to have forward compatible implementations.
// UnimplementedRouteLookupServiceServer should be embedded to have forward compatible implementations.
type UnimplementedRouteLookupServiceServer struct {
}

View File

@ -49,6 +49,7 @@ type Response struct {
// Server is a fake implementation of RLS. It exposes channels to send/receive
// RLS requests and responses.
type Server struct {
rlsgrpc.UnimplementedRouteLookupServiceServer
RequestChan *testutils.Channel
ResponseChan chan Response
Address string

View File

@ -60,6 +60,7 @@ func NewPayload(t testpb.PayloadType, size int) *testpb.Payload {
}
type testServer struct {
testpb.UnimplementedBenchmarkServiceServer
}
func (s *testServer) UnaryCall(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
@ -141,6 +142,7 @@ func (s *testServer) UnconstrainedStreamingCall(stream testpb.BenchmarkService_U
// byteBufServer is a gRPC server that sends and receives byte buffer.
// The purpose is to benchmark the gRPC performance without protobuf serialization/deserialization overhead.
type byteBufServer struct {
testpb.UnimplementedBenchmarkServiceServer
respSize int32
}

View File

@ -108,6 +108,8 @@ func (x *benchmarkServiceUnconstrainedStreamingCallClient) Recv() (*SimpleRespon
}
// BenchmarkServiceServer is the server API for BenchmarkService service.
// All implementations should embed UnimplementedBenchmarkServiceServer
// for forward compatibility
type BenchmarkServiceServer interface {
// One request followed by one response.
// The server returns the client payload as-is.
@ -120,7 +122,7 @@ type BenchmarkServiceServer interface {
UnconstrainedStreamingCall(BenchmarkService_UnconstrainedStreamingCallServer) error
}
// UnimplementedBenchmarkServiceServer can be embedded to have forward compatible implementations.
// UnimplementedBenchmarkServiceServer should be embedded to have forward compatible implementations.
type UnimplementedBenchmarkServiceServer struct {
}
@ -347,6 +349,8 @@ func (c *workerServiceClient) QuitWorker(ctx context.Context, in *Void, opts ...
}
// WorkerServiceServer is the server API for WorkerService service.
// All implementations should embed UnimplementedWorkerServiceServer
// for forward compatibility
type WorkerServiceServer interface {
// Start server with specified workload.
// First request sent specifies the ServerConfig followed by ServerStatus
@ -368,7 +372,7 @@ type WorkerServiceServer interface {
QuitWorker(context.Context, *Void) (*Void, error)
}
// UnimplementedWorkerServiceServer can be embedded to have forward compatible implementations.
// UnimplementedWorkerServiceServer should be embedded to have forward compatible implementations.
type UnimplementedWorkerServiceServer struct {
}

View File

@ -73,6 +73,7 @@ func (byteBufCodec) String() string {
// workerServer implements WorkerService rpc handlers.
// It can create benchmarkServer or benchmarkClient on demand.
type workerServer struct {
testpb.UnimplementedWorkerServiceServer
stop chan<- bool
serverPort int
}

View File

@ -106,6 +106,8 @@ func (c *channelzClient) GetSocket(ctx context.Context, in *GetSocketRequest, op
}
// ChannelzServer is the server API for Channelz service.
// All implementations should embed UnimplementedChannelzServer
// for forward compatibility
type ChannelzServer interface {
// Gets all root channels (i.e. channels the application has directly
// created). This does not include subchannels nor non-top level channels.
@ -124,7 +126,7 @@ type ChannelzServer interface {
GetSocket(context.Context, *GetSocketRequest) (*GetSocketResponse, error)
}
// UnimplementedChannelzServer can be embedded to have forward compatible implementations.
// UnimplementedChannelzServer should be embedded to have forward compatible implementations.
type UnimplementedChannelzServer struct {
}

View File

@ -48,7 +48,9 @@ func newCZServer() channelzgrpc.ChannelzServer {
return &serverImpl{}
}
type serverImpl struct{}
type serverImpl struct {
channelzgrpc.UnimplementedChannelzServer
}
func connectivityStateToProto(s connectivity.State) *channelzpb.ChannelConnectivityState {
switch s {

View File

@ -0,0 +1,21 @@
# protoc-gen-go-grpc
This tool generates Go language bindings of `service`s in protobuf definition
files for gRPC. For usage information, please see our [quick start
guide](https://grpc.io/docs/languages/go/quickstart/).
## Future-proofing services
By default, to register services using the methods generated by this tool, the
service implementations must embed the corresponding
`Unimplemented<ServiceName>Server` for future compatibility. This is a behavior
change from the grpc code generator previously included with `protoc-gen-go`.
To restore this behavior, set the option `requireUnimplementedServers=false`.
E.g.:
```
protoc --go-grpc_out=requireUnimplementedServers=false[,other options...]:. \
```
Note that this is not recommended, and the option is only provided to restore
backward compatibility with previously-generated code.

View File

@ -119,9 +119,16 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated
}
}
mustOrShould := "must"
if !*requireUnimplemented {
mustOrShould = "should"
}
// Server interface.
serverType := service.GoName + "Server"
g.P("// ", serverType, " is the server API for ", service.GoName, " service.")
g.P("// All implementations ", mustOrShould, " embed Unimplemented", serverType)
g.P("// for forward compatibility")
if service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() {
g.P("//")
g.P(deprecationComment)
@ -136,11 +143,14 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated
g.P(method.Comments.Leading,
serverSignature(g, method))
}
if *requireUnimplemented {
g.P("mustEmbedUnimplemented", serverType, "()")
}
g.P("}")
g.P()
// Server Unimplemented struct for forward compatibility.
g.P("// Unimplemented", serverType, " can be embedded to have forward compatible implementations.")
g.P("// Unimplemented", serverType, " ", mustOrShould, " be embedded to have forward compatible implementations.")
g.P("type Unimplemented", serverType, " struct {")
g.P("}")
g.P()
@ -153,6 +163,9 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated
g.P("return ", nilArg, statusPackage.Ident("Errorf"), "(", codesPackage.Ident("Unimplemented"), `, "method `, method.GoName, ` not implemented")`)
g.P("}")
}
if *requireUnimplemented {
g.P("func (*Unimplemented", serverType, ") mustEmbedUnimplemented", serverType, "() {}")
}
g.P()
// Server registration.

View File

@ -31,11 +31,20 @@
package main
import (
"flag"
"google.golang.org/protobuf/compiler/protogen"
)
var requireUnimplemented *bool
func main() {
protogen.Options{}.Run(func(gen *protogen.Plugin) error {
var flags flag.FlagSet
requireUnimplemented = flags.Bool("requireUnimplementedServers", true, "unset to match legacy behavior")
protogen.Options{
ParamFunc: flags.Set,
}.Run(func(gen *protogen.Plugin) error {
for _, f := range gen.Files {
if !f.Generate {
continue

View File

@ -66,6 +66,8 @@ func (x *handshakerServiceDoHandshakeClient) Recv() (*HandshakerResp, error) {
}
// HandshakerServiceServer is the server API for HandshakerService service.
// All implementations should embed UnimplementedHandshakerServiceServer
// for forward compatibility
type HandshakerServiceServer interface {
// Handshaker service accepts a stream of handshaker request, returning a
// stream of handshaker response. Client is expected to send exactly one
@ -76,7 +78,7 @@ type HandshakerServiceServer interface {
DoHandshake(HandshakerService_DoHandshakeServer) error
}
// UnimplementedHandshakerServiceServer can be embedded to have forward compatible implementations.
// UnimplementedHandshakerServiceServer should be embedded to have forward compatible implementations.
type UnimplementedHandshakerServiceServer struct {
}

View File

@ -142,6 +142,8 @@ func (x *echoBidirectionalStreamingEchoClient) Recv() (*EchoResponse, error) {
}
// EchoServer is the server API for Echo service.
// All implementations should embed UnimplementedEchoServer
// for forward compatibility
type EchoServer interface {
// UnaryEcho is unary echo.
UnaryEcho(context.Context, *EchoRequest) (*EchoResponse, error)
@ -153,7 +155,7 @@ type EchoServer interface {
BidirectionalStreamingEcho(Echo_BidirectionalStreamingEchoServer) error
}
// UnimplementedEchoServer can be embedded to have forward compatible implementations.
// UnimplementedEchoServer should be embedded to have forward compatible implementations.
type UnimplementedEchoServer struct {
}

View File

@ -39,12 +39,14 @@ func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...
}
// GreeterServer is the server API for Greeter service.
// All implementations should embed UnimplementedGreeterServer
// for forward compatibility
type GreeterServer interface {
// Sends a greeting
SayHello(context.Context, *HelloRequest) (*HelloReply, error)
}
// UnimplementedGreeterServer can be embedded to have forward compatible implementations.
// UnimplementedGreeterServer should be embedded to have forward compatible implementations.
type UnimplementedGreeterServer struct {
}

View File

@ -158,6 +158,8 @@ func (x *routeGuideRouteChatClient) Recv() (*RouteNote, error) {
}
// RouteGuideServer is the server API for RouteGuide service.
// All implementations should embed UnimplementedRouteGuideServer
// for forward compatibility
type RouteGuideServer interface {
// A simple RPC.
//
@ -185,7 +187,7 @@ type RouteGuideServer interface {
RouteChat(RouteGuide_RouteChatServer) error
}
// UnimplementedRouteGuideServer can be embedded to have forward compatible implementations.
// UnimplementedRouteGuideServer should be embedded to have forward compatible implementations.
type UnimplementedRouteGuideServer struct {
}

View File

@ -88,6 +88,8 @@ func (x *healthWatchClient) Recv() (*HealthCheckResponse, error) {
}
// HealthServer is the server API for Health service.
// All implementations should embed UnimplementedHealthServer
// for forward compatibility
type HealthServer interface {
// If the requested service is unknown, the call will fail with status
// NOT_FOUND.
@ -110,7 +112,7 @@ type HealthServer interface {
Watch(*HealthCheckRequest, Health_WatchServer) error
}
// UnimplementedHealthServer can be embedded to have forward compatible implementations.
// UnimplementedHealthServer should be embedded to have forward compatible implementations.
type UnimplementedHealthServer struct {
}

View File

@ -33,6 +33,7 @@ import (
// Server implements `service Health`.
type Server struct {
healthgrpc.UnimplementedHealthServer
mu sync.RWMutex
// If shutdown is true, it's expected all serving status is NOT_SERVING, and
// will stay in NOT_SERVING.

View File

@ -48,6 +48,7 @@ var (
)
type loadBalancerServer struct {
lbpb.UnimplementedLoadBalancerServer
serverListResponse *lbpb.LoadBalanceResponse
}

View File

@ -194,6 +194,8 @@ func (x *testServiceHalfDuplexCallClient) Recv() (*StreamingOutputCallResponse,
}
// TestServiceServer is the server API for TestService service.
// All implementations should embed UnimplementedTestServiceServer
// for forward compatibility
type TestServiceServer interface {
// One empty request followed by one empty response.
EmptyCall(context.Context, *Empty) (*Empty, error)
@ -217,7 +219,7 @@ type TestServiceServer interface {
HalfDuplexCall(TestService_HalfDuplexCallServer) error
}
// UnimplementedTestServiceServer can be embedded to have forward compatible implementations.
// UnimplementedTestServiceServer should be embedded to have forward compatible implementations.
type UnimplementedTestServiceServer struct {
}
@ -445,12 +447,14 @@ func (c *unimplementedServiceClient) UnimplementedCall(ctx context.Context, in *
}
// UnimplementedServiceServer is the server API for UnimplementedService service.
// All implementations should embed UnimplementedUnimplementedServiceServer
// for forward compatibility
type UnimplementedServiceServer interface {
// A call that no server should implement
UnimplementedCall(context.Context, *Empty) (*Empty, error)
}
// UnimplementedUnimplementedServiceServer can be embedded to have forward compatible implementations.
// UnimplementedUnimplementedServiceServer should be embedded to have forward compatible implementations.
type UnimplementedUnimplementedServiceServer struct {
}
@ -519,12 +523,14 @@ func (c *loadBalancerStatsServiceClient) GetClientStats(ctx context.Context, in
}
// LoadBalancerStatsServiceServer is the server API for LoadBalancerStatsService service.
// All implementations should embed UnimplementedLoadBalancerStatsServiceServer
// for forward compatibility
type LoadBalancerStatsServiceServer interface {
// Gets the backend distribution for RPCs sent by a test client.
GetClientStats(context.Context, *LoadBalancerStatsRequest) (*LoadBalancerStatsResponse, error)
}
// UnimplementedLoadBalancerStatsServiceServer can be embedded to have forward compatible implementations.
// UnimplementedLoadBalancerStatsServiceServer should be embedded to have forward compatible implementations.
type UnimplementedLoadBalancerStatsServiceServer struct {
}

View File

@ -672,6 +672,7 @@ func DoPickFirstUnary(tc testpb.TestServiceClient) {
}
type testServer struct {
testpb.UnimplementedTestServiceServer
}
// NewTestServer creates a test server for test service.

View File

@ -60,7 +60,9 @@ var (
watchers = make(map[statsWatcherKey]*statsWatcher)
)
type statsService struct{}
type statsService struct {
testpb.UnimplementedLoadBalancerStatsServiceServer
}
// Wait for the next LoadBalancerStatsRequest.GetNumRpcs to start and complete,
// and return the distribution of remote peers. This is essentially a clientside

View File

@ -51,6 +51,8 @@ func (c *profilingClient) GetStreamStats(ctx context.Context, in *GetStreamStats
}
// ProfilingServer is the server API for Profiling service.
// All implementations should embed UnimplementedProfilingServer
// for forward compatibility
type ProfilingServer interface {
// Enable allows users to toggle profiling on and off remotely.
Enable(context.Context, *EnableRequest) (*EnableResponse, error)
@ -59,7 +61,7 @@ type ProfilingServer interface {
GetStreamStats(context.Context, *GetStreamStatsRequest) (*GetStreamStatsResponse, error)
}
// UnimplementedProfilingServer can be embedded to have forward compatible implementations.
// UnimplementedProfilingServer should be embedded to have forward compatible implementations.
type UnimplementedProfilingServer struct {
}

View File

@ -76,6 +76,7 @@ func Init(pc *ProfilingConfig) error {
}
type profilingServer struct {
ppb.UnimplementedProfilingServer
drainMutex sync.Mutex
}

View File

@ -62,13 +62,15 @@ func (x *serverReflectionServerReflectionInfoClient) Recv() (*ServerReflectionRe
}
// ServerReflectionServer is the server API for ServerReflection service.
// All implementations should embed UnimplementedServerReflectionServer
// for forward compatibility
type ServerReflectionServer interface {
// The reflection service is structured as a bidirectional stream, ensuring
// all related requests go to a single server.
ServerReflectionInfo(ServerReflection_ServerReflectionInfoServer) error
}
// UnimplementedServerReflectionServer can be embedded to have forward compatible implementations.
// UnimplementedServerReflectionServer should be embedded to have forward compatible implementations.
type UnimplementedServerReflectionServer struct {
}

View File

@ -70,12 +70,14 @@ func (x *searchServiceStreamingSearchClient) Recv() (*SearchResponse, error) {
}
// SearchServiceServer is the server API for SearchService service.
// All implementations should embed UnimplementedSearchServiceServer
// for forward compatibility
type SearchServiceServer interface {
Search(context.Context, *SearchRequest) (*SearchResponse, error)
StreamingSearch(SearchService_StreamingSearchServer) error
}
// UnimplementedSearchServiceServer can be embedded to have forward compatible implementations.
// UnimplementedSearchServiceServer should be embedded to have forward compatible implementations.
type UnimplementedSearchServiceServer struct {
}

View File

@ -55,6 +55,7 @@ import (
)
type serverReflectionServer struct {
rpb.UnimplementedServerReflectionServer
s *grpc.Server
initSymbols sync.Once

View File

@ -57,7 +57,7 @@ SOURCES=(
OPTS=Mgrpc/service_config/service_config.proto=/internal/proto/grpc_service_config
for src in ${SOURCES[@]}; do
echo "protoc ${src}"
protoc --go_out=${OPTS}:${WORKDIR}/out --go-grpc_out=${OPTS}:${WORKDIR}/out \
protoc --go_out=${OPTS}:${WORKDIR}/out --go-grpc_out=${OPTS},requireUnimplementedServers=false:${WORKDIR}/out \
-I"." \
-I${WORKDIR}/grpc-proto \
-I${WORKDIR}/googleapis \

View File

@ -145,6 +145,8 @@ func (x *testServiceServerStreamCallClient) Recv() (*SimpleResponse, error) {
}
// TestServiceServer is the server API for TestService service.
// All implementations should embed UnimplementedTestServiceServer
// for forward compatibility
type TestServiceServer interface {
// One request followed by one response.
// The server returns the client id as-is.
@ -159,7 +161,7 @@ type TestServiceServer interface {
ServerStreamCall(*SimpleRequest, TestService_ServerStreamCallServer) error
}
// UnimplementedTestServiceServer can be embedded to have forward compatible implementations.
// UnimplementedTestServiceServer should be embedded to have forward compatible implementations.
type UnimplementedTestServiceServer struct {
}

View File

@ -144,6 +144,7 @@ func (g *gauge) get() int64 {
// server implements metrics server functions.
type server struct {
metricspb.UnimplementedMetricsServiceServer
mutex sync.RWMutex
// gauges is a map from /stress_test/server_<n>/channel_<n>/stub_<n>/qps to its qps gauge.
gauges map[string]*gauge

View File

@ -74,6 +74,8 @@ func (c *metricsServiceClient) GetGauge(ctx context.Context, in *GaugeRequest, o
}
// MetricsServiceServer is the server API for MetricsService service.
// All implementations should embed UnimplementedMetricsServiceServer
// for forward compatibility
type MetricsServiceServer interface {
// Returns the values of all the gauges that are currently being maintained by
// the service
@ -82,7 +84,7 @@ type MetricsServiceServer interface {
GetGauge(context.Context, *GaugeRequest) (*GaugeResponse, error)
}
// UnimplementedMetricsServiceServer can be embedded to have forward compatible implementations.
// UnimplementedMetricsServiceServer should be embedded to have forward compatible implementations.
type UnimplementedMetricsServiceServer struct {
}

View File

@ -194,6 +194,8 @@ func (x *testServiceHalfDuplexCallClient) Recv() (*StreamingOutputCallResponse,
}
// TestServiceServer is the server API for TestService service.
// All implementations should embed UnimplementedTestServiceServer
// for forward compatibility
type TestServiceServer interface {
// One empty request followed by one empty response.
EmptyCall(context.Context, *Empty) (*Empty, error)
@ -217,7 +219,7 @@ type TestServiceServer interface {
HalfDuplexCall(TestService_HalfDuplexCallServer) error
}
// UnimplementedTestServiceServer can be embedded to have forward compatible implementations.
// UnimplementedTestServiceServer should be embedded to have forward compatible implementations.
type UnimplementedTestServiceServer struct {
}