如何在 Python gRPC 处理程序中访问方法名称

Posted

技术标签:

【中文标题】如何在 Python gRPC 处理程序中访问方法名称【英文标题】:How to access the method name in a Python gRPC handler 【发布时间】:2020-08-01 00:50:57 【问题描述】:

我正在尝试从 gRPC 处理程序中访问方法名称 service/Method。我似乎无法在 grpc.ServicerContext 对象上找到这些数据(而且我很确定它不存在)。我的下一个想法是使用拦截器,因为方法名称是通过grpc.HandlerCallDetails 提供的。问题是没有任何明显的方法可以将此转发给底层处理程序。

不幸的是,grpc.HandlerCallDetails 没有构造函数,因此我们不能将方法名称放入元数据中以便在处理程序中读取。我们必须创建一个命名元组,它与grpc.HandlerCallDetails 的接口相同,并向其中添加一个新的元数据值。

如果有人遇到此问题并有解决方案,或者 grpc 团队中的某个人有解决方法,那就太好了。

此外,这可能会更容易一些,因为此类功能已有现有技术。 grpc-goMethod 名称来帮助解决这个 https://pkg.go.dev/google.golang.org/grpc?tab=doc#Method。在 C++ 中,您似乎可以将其从人口普查上下文中拉出来。

【问题讨论】:

【参考方案1】:

我认为您找到了正确的组件。 HandlerCallDetails用于让gRPC servicer匹配方法名和handler。

一种可能的方法是通过实现ServiceRpcHandler。您可以实现自己的处理程序并将其提供给 gRPC 服务器。在服务处理程序中,您可以提供方法名称信息作为第三个参数,或者将其附加到服务上下文,或者分配给线程本地存储。

此外,ProtoBuf 生成的代码隐藏了这个细节,可以很好地参考它是如何完成的。

这里是一份 ProtoBuf 生成的代码:

def add_GreeterServicer_to_server(servicer, server):
  rpc_method_handlers = 
      'SayHello': grpc.unary_unary_rpc_method_handler(
          servicer.SayHello,
          request_deserializer=helloworld__pb2.HelloRequest.FromString,
          response_serializer=helloworld__pb2.HelloReply.SerializeToString,
      ),
  
  generic_handler = grpc.method_handlers_generic_handler(
      'helloworld.Greeter', rpc_method_handlers)
  server.add_generic_rpc_handlers((generic_handler,))

这是默认的服务 RPC 处理程序implementation:

class DictionaryGenericHandler(grpc.ServiceRpcHandler):

    def __init__(self, service, method_handlers):
        self._name = service
        self._method_handlers = 
            _common.fully_qualified_method(service, method): method_handler
            for method, method_handler in six.iteritems(method_handlers)
        

    def service_name(self):
        return self._name

    def service(self, handler_call_details):
        return self._method_handlers.get(handler_call_details.method)

【讨论】:

感谢您的回答,但似乎这种方法需要放弃生成的 protobuf 代码。我的解决方案是使用 metaclasses + abc 强制我的基本 Servicer mixin 的子类手动指定服务名称(通过描述符获取),然后只使用当前 python 方法的名称,因为它与 gRPC 方法名称和然后将它们加入我的装饰器中,该装饰器包装了所有 gRPC 方法。感觉很 hacky,生成的代码应该会让这更容易一些。

以上是关于如何在 Python gRPC 处理程序中访问方法名称的主要内容,如果未能解决你的问题,请参考以下文章

Go 程序员如何使用 gRPC 的指南

如何使用Python gRPC处理流式消息

Grpc使用grpc配置通过端口访问的python服务

Grpc使用grpc配置通过端口访问的python服务

grpc-java的ServerBuilder中executor的具体用途是啥?它只是执行处理程序方法吗?

如何知道 SERVER 端的 gRPC 函数处理程序中连接的真实地址(哪个 NIC)?