vmagamedov / grpclib

Pure-Python gRPC implementation for asyncio
http://grpclib.readthedocs.io
BSD 3-Clause "New" or "Revised" License
938 stars 91 forks source link

ServerReflection not working correctly #172

Closed ih3xcode closed 1 year ago

ih3xcode commented 1 year ago

I followed the documentation to configure Reflection in my project. Here is the relevant code:

services = [AuthService(settings)]
services = ServerReflection.extend(services)
server = Server(services)

However, when I try to list the services using grpc_cli, I get following results:

$ grpc_cli ls 127.0.0.1:8080
ua.h3xcode.naudata.auth.AuthService
$ grpc_cli ls 127.0.0.1:8080 ua.h3xcode.naudata.auth.AuthService
Service or method ua.h3xcode.naudata.auth.AuthService not found.

grpclib version: 0.4.3

vmagamedov commented 1 year ago

I don't have grpc_cli installed, I tested with grpcurl:

$ grpcurl -plaintext localhost:50051 list
helloworld.Greeter
$ grpcurl -plaintext localhost:50051 list helloworld.Greeter
helloworld.Greeter.SayHello
$ grpcurl -plaintext localhost:50051 describe helloworld.Greeter.SayHello
helloworld.Greeter.SayHello is a method:
rpc SayHello ( .helloworld.HelloRequest ) returns ( .helloworld.HelloReply );
ih3xcode commented 1 year ago

Same with grpcurl. Here is minimal reproducible example:

hello.proto:

syntax = "proto3";

package hello;

message SayHelloRequest { string name = 1; }

message SayHelloResponse { string message = 1; }

service HelloService {
  rpc SayHello(SayHelloRequest) returns (SayHelloResponse) {}
}

compilation command:

mkdir -v proto
python -m grpc_tools.protoc -I. --python_betterproto_out=proto hello.proto

server.py:

import logging

from proto.hello import HelloServiceBase, SayHelloRequest, SayHelloResponse

from grpclib.server import Server
from grpclib.reflection.service import ServerReflection

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class HelloService(HelloServiceBase):
    async def say_hello(self, request: SayHelloRequest) -> SayHelloResponse:
        return SayHelloResponse(message=f"Hello {request.name}")

async def main() -> None:
    services = [HelloService()]
    services = ServerReflection.extend(services)

    server = Server(services)
    await server.start("localhost", 50051)
    logger.info("Server started")
    await server.wait_closed()

if __name__ == "__main__":
    import asyncio

    asyncio.run(main())

grpcurl output:

$ grpcurl -plaintext localhost:50051 list
hello.HelloService
$ grpcurl -plaintext localhost:50051 list hello.HelloService
Failed to list methods for service "hello.HelloService": Symbol not found: hello.HelloService

grpcio-tools v1.51.3 grpclib v0.4.3 betterproto v2.0.0b5

vmagamedov commented 1 year ago

gRPC reflection rely on a "registry" (google.protobuf.descriptor_pool) where all imported protobuf messages and services are registered.

You use betterproto instead of protobuf and looks like that this registry is empty in this case.

vmagamedov commented 1 year ago

Here is related issue: https://github.com/danielgtaylor/python-betterproto/issues/443