grpc with mustEmbedUnimplemented*** method
Asked Answered
H

3

29

Recently, grpc-go introduced the mustEmbedUnimplemented*** method. It is used for forward compatibility.

In simple terms, I am unable to understand how it is helping and how earlier without it what problems we were facing? In my structs now I use to add the following statement but, I don't know why...

type server struct {
     pdfpb.UnimplementedGreetServiceServer
}

In Github issue - https://github.com/grpc/grpc-go/issues/3669 they debated over it, can someone please explain in simple terms how it is helping and how earlier without it what problems we were facing?

Hellbent answered 30/11, 2020 at 18:18 Comment(0)
F
23

This error comes newer versions of the protoc-gen-grpc-go compiler. Server implementations must now be forward-compatible.

Before this change, whenever you registered a server implementation, you would do something like this:

        pb.RegisterFooBarServiceServer(
            server,
            &FooBarServer{}, // or whatever you use to construct the server impl
        )

Which would result in a compile-time error in case your server has some missing method implementations.

With the newer proto compiler version, forward-compatibility becomes opt-out, which means two things:

  1. you must now embed UnimplementedFooBarServiceServer, as the error message suggests. As I said, this will not produce compiler errors when you do not explicitly implement new methods (this is what forward compatibility means). Though it will result in a run-time error with codes.Unimplemented if you attempt to call an RPC that you didn't (or forgot) to explicitly implement.

  2. you can still opt-out of forward compatibility by embedding instead UnsafeFooBarServiceServer (with Unsafe prefix). This interface simply declares the mustEmbedUnimplementedFooBarServiceServer() method which makes the error in the question go away, without forgoing a compiler errors in case you didn't explicitly implement the new handlers.

So for example:

// Implements the grpc FooBarServiceServer
type FooBarService struct {
    grpc.UnsafeFooBarServiceServer // consciously opt-out of forward compatibility
    // other fields
}

You can also generate code without forward compatibility by setting an option on protoc-gen-grpc-go plugin (source):

protoc --go-grpc_out=require_unimplemented_servers=false:.

Note the :. after the --go-grpc_out option is used to set the path element.

Furring answered 7/10, 2021 at 11:19 Comment(0)
H
8

That was quite basic.

UnimplementedGreetServiceServer is a struct with all implemented methods.

When I add pdfpb.UnimplementedGreetServiceServer I am able to call UnimplementedGreetServiceServer defined methods.

That's how, if I add more RPC services in the proto file, then I don't need to add all RPC methods leading to forward compatibility.

Demo code is available at: https://github.com/parthw/fun-coding/tree/main/golang/understanding-grpc-change

Hellbent answered 1/12, 2020 at 16:58 Comment(2)
So what is this actually helping? I'm definitely of the opinion that this isn't a feature and can cause breaking APIs. Why would I want to allow the generation of proto files into go files and not have them be implemented?Jobless
@Jobless I agree with you. I don't want RPCs failing with Unimplemented in case someone forgets to implement a handler. However there is a benefit in this change, which is that now you must make a conscious choice about whether to have forward compatibility or not. On the other side, you may not want failing builds whenever you upgrade the proto schema but not the grpc implementation. So they let you choose. Anyway you can still opt-out of fwd compat. See my answer for detailsFurring
N
5

For anyone that still have problems with mustEmbededUnimplementedServiceServer as suggested on the Github Issue. the best solution is just to update your ServerStruct.

Ex.

type AuthenticationServiceServer struct {
}

To.

type AuthenticationServiceServer struct {
    service.UnimplementedAuthenticationServiceServer
}

that will solve the exception throw by Go when doing this.

grpcService.RegisterAuthenticationServiceServer(grpcServer, controller.AuthenticationServiceServer{})
Noticeable answered 23/9, 2021 at 15:18 Comment(1)
Example code here github.com/alexcpn/go_grpc_2022Probate

© 2022 - 2025 — McMap. All rights reserved.