0

I've recently updated to the latest protoc and Go plugins with an existing proto 3 codebase, and am running into trouble with the new UnimplementedServer functionality. The struct that is used for the Grpc server already embeds another interface describing the methods implemented by this service. After embedding the UnimplementedServer reference in my struct, I get an ambiguous error from the compiler and it tells me I am not implementing my service method anymore. Is there some issue with the way I have structured the code? Code to reproduce follows, with libprotoc 3.17.3, protoc-gen-go v1.27.1, and protoc-gen-go-grpc 1.1.0: api/proto/core_service.proto:


package testbed;

option go_package = "internal/proto";

service Core {
    rpc CreateThing(Thing) returns (ThingResponse) {};
}

message Thing {
    string name = 1;
}

message ThingResponse {
    int64 result = 1;
}

internal/core.go:


import (
    "context"

    "testbed.org/demo/internal/proto"
)

type CoreApi interface {
    CreateThing(ctx context.Context, t *proto.Thing) (*proto.ThingResponse, error)
}

internal/core_endpoints.go:


import (
    "context"

    "testbed.org/demo/internal/proto"
)

type CoreEndpoints struct {}

func (ce CoreEndpoints) CreateThing(_ context.Context, _ *proto.Thing) (*proto.ThingResponse, error) {
    return nil, nil
}

cmd/service.go:


import (
    //"context"
    . "testbed.org/demo/internal"
    "testbed.org/demo/internal/proto"
    "google.golang.org/grpc"
)

type MyServer struct {
    CoreApi
    proto.UnimplementedCoreServer
}

func main() {
    mySvr := &MyServer{CoreApi: &CoreEndpoints{}}
    //_, _ = mySvr.CoreApi.CreateThing(context.Background(), &proto.Thing{})
    grpcSvr := grpc.NewServer()
    proto.RegisterCoreServer(grpcSvr, mySvr)
}

Build:

protoc -I api/proto/ api/proto/*.proto --go_out=. --go-grpc_out=.
go build -o bin/svc cmd/service.go
cmd/service.go:19:26: MyServer.CreateThing is ambiguous
cmd/service.go:19:26: cannot use mySvr (type *MyServer) as type "testbed.org/demo/internal/proto".CoreServer in argument to "testbed.org/demo/internal/proto".RegisterCoreServer:
    *MyServer does not implement "testbed.org/demo/internal/proto".CoreServer (missing CreateThing method)
gmake: *** [Makefile:8: service] Error 2
Jeffe
  • 31
  • 4
  • Don't think that there is currently a good solution to this; it was covered in [this issue](https://github.com/grpc/grpc-go/issues/3794#issuecomment-834907278). If you are OK with opting out of forward compatibility you can embed `UnsafeCoreServer` instead of `UnimplementedCoreServer`. – Brits Aug 10 '21 at 21:58

1 Answers1

1

As the log says, 'Myserver' does not implement the coreserver interface.

type MyServer struct {
    endpoint CoreEndpoints
    proto.UnimplementedCoreServer
}

func (srv MyServer) CreateThing(ctx context.Context, in *proto.Thing)(*proto.ThingResponse, error) {
    return srv.endpoint.CreateThing(ctx,in)
}

Trock
  • 546
  • 2
  • 13
  • Thanks Trock - so that means that I need to re-implement every one of the service methods with a wrapper like this that calls the real implementation? The reason for the way the code is organized today is, in part, because we don't want the GrpcServer struct to have to know about all of the business methods. Perhaps the require_unimplemented_servers=false flag is a better choice for this implementation? – Jeffe Aug 10 '21 at 21:47
  • 1
    Welcome, I may not have enough experience.I think re-implement is much better in some scenes. For example, I defined GrpcServer and HTTPServer to wrap the endpoint like MyServer. Secondary encapsulation of the results of the endpoint. So I only need to implement endpoint once, but I can easily implement grpc and HTTP services. – Trock Aug 11 '21 at 08:27