yarpc / yarpc-go

A message passing platform for Go
MIT License
403 stars 101 forks source link

grpc example not running #1936

Closed Choongkyu closed 4 years ago

Choongkyu commented 4 years ago

Hello. I am trying to get the keyvalue-thrift example working with grpc and after having compiled a proto file, I'm unable to run it and get the following error:

server/main.go:84:62: cannot use server (type *Server) as type keyvalue.KeyValueYARPCServer in argument to keyvalue.BuildKeyValueYARPCProcedures:
    *Server does not implement keyvalue.KeyValueYARPCServer (missing keyvalue.getValue method)
        have getValue(context.Context, *keyvalue.GetValueRequest) (*keyvalue.GetValueResponse, error)
        want keyvalue.getValue(context.Context, *keyvalue.GetValueRequest) (*keyvalue.GetValueResponse, error)

The altered version of thrift-keyvalue is as follows:

func main() {
    if err := do(); err != nil {
        log.Fatal(err)
    }
}

type Server struct{
    sync.RWMutex
    items map[string]string
}

func NewServer() *Server {
    return &Server{
        items: make(map[string]string),
    }
}

func (f *Server) getValue(ctx context.Context, req *keyvaluefoo.GetValueRequest) (*keyvaluefoo.GetValueResponse, error) {
    return &keyvaluefoo.GetValueResponse{
        Response: &keyvaluefoo.GetValueResponse_Success{
            &keyvaluefoo.Success{
                Value: f.items[req.Key],
            },
        },
    }, nil
}

func do() error {

    logger := zap.NewExample()

    listener, err := net.Listen("tcp", "127.0.0.1:24046")
    if err != nil {
        return err
    }
    grpcinbound := grpc.NewTransport(grpc.Logger(logger)).NewInbound(listener)

    dispatcher := yarpc.NewDispatcher(yarpc.Config{
        Name: "keyvalue",
        Inbounds: yarpc.Inbounds{
            grpcinbound,
        },
        Logging: yarpc.LoggingConfig{
            Zap: logger,
        },
    })

    var server = NewServer()
    dispatcher.Register(keyvaluefoo.BuildKeyValueYARPCProcedures(server))

    yarpcmeta.Register(dispatcher)

    if err := dispatcher.Start(); err != nil {
        return err
    }

    select {}
}

and the proto file:

syntax = "proto3";
package keyvalue;

message GetValueRequest {
  string key = 1;
}

enum ErrorCode {
  ERROR_CODE_INVALID = 0;
}

message Success {
  string value = 1;
}

message GetValueResponse{
  message ResourceDoesNotExist {
    ErrorCode error_code = 1;
    string key = 2;
    string message = 3;
  }
  oneof response {
    Success success = 1;
    ResourceDoesNotExist doesNotExist = 2;
  }
}

message SetValueRequest {
  string key = 1;
  string value = 2;
}

message SetValueResponse {}

service KeyValue {
    rpc getValue(GetValueRequest) returns (GetValueResponse) {}
    rpc setValue(SetValueRequest) returns (SetValueResponse) {}
}
peats-bond commented 4 years ago

Hey @zebralight, we do have gRPC examples that already exist here:

It's hard to tell what's happening without the full context of the generated code, but it seems like your Server does not implement the generated YARPC interface.

Please check out the examples and re-open if you have any questions!

Choongkyu commented 4 years ago

hi @AlexAPB. thank you for the response. I made the advised change of setting getValue to be public but am seeing the same error issued which was:

server/main.go:89:62: cannot use server (type *Server) as type keyvalue.KeyValueYARPCServer in argument to keyvalue.BuildKeyValueYARPCProcedures:
    *Server does not implement keyvalue.KeyValueYARPCServer (missing keyvalue.getValue method)
        have GetValue(context.Context, *keyvalue.GetValueRequest) (*keyvalue.GetValueResponse, error)
        want keyvalue.getValue(context.Context, *keyvalue.GetValueRequest) (*keyvalue.GetValueResponse, error)

. I've also added SetValue and didn't include it in the original ticket since the error was only alerting me about getValue.

I just tried out the protobuf example and tried running it and then calling it with this yab:

service: example
method: EchoIn
peer: grpc://127.0.0.1:34111
timeout: 1000ms
request:
  message: "foo"
  num_responses: 3

and am getting this response:

Failed while parsing input: rpc error: code = Unimplemented desc = unrecognized procedure "grpc.reflection.v1alpha.ServerReflection::ServerReflectionInfo" for service "example"

thanks again!

peats-bond commented 4 years ago

Ah, so you've actually run into two interesting edge cases.

The first issue is that your Protobuf file is defining methods using camelCase instead of PascalCase (ie setFoo instead of SetFoo). This is causing YARPC's protoc plugin to generate private methods on the interface, which are unimplementable if generated into a separate package. At Uber, we don't run into this issue since we have linters than enforce methods to be PascalCase.

Next, internally some services use an Fx layer that enables the gRPC reflection protocol. Since you are not hooking up the reflection server manually, you'll need to use protoc and pass the FileDescriptorSet using -F (I do not recall if this works with yab-YAML files)

$ yab --help
...
-F, --file-descriptor-set-bin= A binary file containing a compiled protobuf FileDescriptorSet.
Choongkyu commented 4 years ago

thank you very much! Swapping to pascal case and adding that flag fixed both issues.