Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 8 commits into from
Jun 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion balancer/grpclb/grpc_lb_v1/load_balancer_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions balancer/grpclb/grpclb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ func (s *rpcStats) String() string {
}

type remoteBalancer struct {
lbgrpc.UnimplementedLoadBalancerServer
sls chan *lbpb.ServerList
statsDura time.Duration
done chan struct{}
Expand Down
4 changes: 3 additions & 1 deletion balancer/rls/internal/proto/grpc_lookup_v1/rls_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions balancer/rls/internal/testutils/fakeserver/fakeserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions benchmark/benchmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
}

Expand Down
8 changes: 6 additions & 2 deletions benchmark/grpc_testing/services_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions benchmark/worker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 3 additions & 1 deletion channelz/grpc_channelz_v1/channelz_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion channelz/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
21 changes: 21 additions & 0 deletions cmd/protoc-gen-go-grpc/README.md
Original file line number Diff line number Diff line change
@@ -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/).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick start doesn't have examples for using this plugin (yet?)

Even if it does, it would be helpful to have a copy-paste ready command here?
Or point to https://github.com/grpc/grpc-go/blob/master/regenerate.sh#L60

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation is very much a work in progress. Let's make incremental progress on it until we eventually release the tool at 1.0.


## Future-proofing services

By default, to register services using the methods generated by this tool, the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to a separate section?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

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.
15 changes: 14 additions & 1 deletion cmd/protoc-gen-go-grpc/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
Expand All @@ -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.
Expand Down
11 changes: 10 additions & 1 deletion cmd/protoc-gen-go-grpc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion examples/features/proto/echo/echo_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion examples/helloworld/helloworld/helloworld_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion examples/route_guide/routeguide/route_guide_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion health/grpc_health_v1/health_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions health/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions interop/fake_grpclb/fake_grpclb.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ var (
)

type loadBalancerServer struct {
lbpb.UnimplementedLoadBalancerServer
serverListResponse *lbpb.LoadBalanceResponse
}

Expand Down
12 changes: 9 additions & 3 deletions interop/grpc_testing/test_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions interop/test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ func DoPickFirstUnary(tc testpb.TestServiceClient) {
}

type testServer struct {
testpb.UnimplementedTestServiceServer
}

// NewTestServer creates a test server for test service.
Expand Down
4 changes: 3 additions & 1 deletion interop/xds/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading