Как получить доступ к имени метода в обработчике Python gRPC

Я пытаюсь получить доступ к имени метода service/Method из обработчика gRPC. Кажется, я не могу найти эти данные на объекте grpc.ServicerContext (и я почти уверен, что их там нет). Следующей моей мыслью было использовать перехватчик, поскольку имя метода предоставляется через grpc.HandlerCallDetails. Проблема в том, что нет очевидного способа передать это базовому обработчику.

К сожалению, у grpc.HandlerCallDetails нет конструктора, поэтому мы не можем взять имя метода и засунуть его в метаданные, чтобы оно было прочитано в обработчике. Нам нужно будет создать именованный кортеж с тем же интерфейсом, что и grpc.HandlerCallDetails, и добавить к нему новое значение метаданных.

Было бы здорово, если бы кто-нибудь столкнулся с этим и нашел решение, или если у кого-то из команды grpc есть обходной путь.

Кроме того, это, вероятно, должно быть что-то более простое, поскольку для такого рода функций уже существует уровень техники. grpc-go имеет имя Method, чтобы помочь с этим https://pkg.go.dev/google.golang.org/grpc?tab=doc#Method. Похоже, что в C ++ вы потенциально можете вытащить это из контекста переписи.


person Andrew Braunstein    schedule 01.08.2020    source источник


Ответы (1)


Думаю, вы нашли нужный компонент. HandlerCallDetails используется, чтобы позволить серверу gRPC сопоставить имя метода и обработчик.

Один из возможных способов сделать это - реализовать 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 службы по умолчанию, реализация "norefer".:

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)
person Lidi Zheng    schedule 03.08.2020
comment
Спасибо за ответ, но похоже, что этот подход потребует отказа от сгенерированного кода protobuf. Мое решение заключалось в том, чтобы использовать метаклассы + abc, чтобы заставить подклассы моего базового миксина Servicer указывать имя службы вручную (полученное через дескриптор), а затем просто использовать имя текущего метода python, поскольку оно совпадает с именем метода gRPC и затем объедините их в моем декораторе, который обертывает все методы gRPC. Кажется очень хакерским, и сгенерированный код, вероятно, должен сделать это немного проще. - person Andrew Braunstein; 04.08.2020