如何在 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-go
有 Method
名称来帮助解决这个 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 处理程序中访问方法名称的主要内容,如果未能解决你的问题,请参考以下文章