gRPC-python: переключение Servicer во время работы сервера gRPC? (симуляция - переключение реального режима) - PullRequest
0 голосов
/ 22 января 2019

Для нашего нового открытого стандарта автоматизации лабораторных устройств (https://gitlab.com/SiLA2/sila_python)) мы хотели бы запустить устройства (= серверы gRPC) в двух режимах: режиме моделирования и реальном режиме (с одинаковым набором удаленных вызовов). , но в первом случае он должен просто возвращать смоделированные ответы, во втором он должен связываться с оборудованием.

Моя первая идея состояла в том, чтобы создать два почти идентичных класса Python обслуживающего устройства gRPC в отдельных модулях, как в этом примере:

in hello_sim.py :

class SayHello(SayHello_pb2_grpc.SayHelloServicer):
  #... implementation of the simulation servicer
  def SayHello(self, request, context):
  # simulation code ...
  return SayHello_pb2.SayHello_response("simulation")

in hello_real.py :

class SayHello(SayHello_pb2_grpc.SayHelloServicer):
  #... implementation of the real servicer
  def SayHello(self, request, context):
  # real hardware code
  return SayHello_pb2.SayHello_response("real")

и затем, после создания сервера gRPC в server.py, я мог переключаться между симуляцией и реальным режимом путем повторной регистрации сервера на сервере gRPC, например ::

server.py

# imports, init ...

grpc_server = GRPCServer(ThreadPoolExecutor(max_workers=10)) 

sh_sim = SayHello_sim.SayHello()
sh_real = SayHello_real.SayHello()

SayHello_pb2_grpc.add_SayHelloServicer_to_server(sh_sim, grpc_server)

grpc_server.run()

# ..... and later, still while the same grpc server is running, re-register, like

SayHello_pb2_grpc.add_SayHelloServicer_to_server(sh_real, grpc_server)

для возможности вызова реального аппаратного кода; или путем обмена ссылкой на объект обслуживающего устройства, например, например ::1010*

# imports, init ...

grpc_server = GRPCServer(ThreadPoolExecutor(max_workers=10)) 

sh_sim = SayHello_sim.SayHello()
sh_real = SayHello_real.SayHello()

sh_current = sh_sim

SayHello_pb2_grpc.add_SayHelloServicer_to_server(sh_current , grpc_server)

grpc_server.run()

# ..... and then later, still while the same grpc server is running, re-register the real Servicer, like

sh_current = sh_real    
#  so that the server would just use the other servicer object for the next calls ...

но обе стратегии не работают: (

При вызове сервера в режиме симуляции из клиента gRPC, я ожидаю, что он должен ответить (в соответствии с примером): "имитация"

gRPC_client.py

# imports, init ....

response = self.SayHello_stub.SayHello()
print(response)
>'simulation'

и после перехода в реальный режим (любым механизмом) «реальный»:

# after switching to real mode ...
response = self.SayHello_stub.SayHello()
print(response)
>'real'

Какое самое чистое и элегантное решение для переключения этого режима без полного выключения сервера gRPC (и тем самым потери соединения с клиентом)?

Заранее большое спасибо за помощь!

PS: (Завершение работы сервера gRPC и перерегистрация, конечно, будет работать, но это не то, чего мы хотим.)

1 Ответ

0 голосов
/ 23 января 2019

Добрый мой коллега дал мне хорошее предложение: Можно использовать концепцию внедрения зависимостей (s. https://en.wikipedia.org/wiki/Dependency_injection), вроде:

class SayHello(pb2_grpc.SayHelloServicer):
    def inject_implementation(SayHelloImplmentation):
      self.implementation = SayHelloImplementation;

   def SayHello(self, request, context):
      return self.implementation.sayHello(request, context)

для полного примера см. https://gitlab.com/SiLA2/sila_python/tree/master/examples/simulation_real_mode_demo

...