gRPC python:在gRPC服务器运行时切换Servicer?(模拟-真实模式切换)



对于我们新的开放式实验室设备自动化标准(https://gitlab.com/SiLA2/sila_python)我们想在两种模式下运行设备(=gRPC服务器):模拟模式和真实模式(使用相同的远程调用集,但在第一种情况下,它只会在第二种情况下返回模拟响应,它应该与硬件通信

我的第一个想法是在分离的模块中创建两个几乎相同的gRPC服务程序python类,如本例所示:

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")

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")

然后,在server.py中创建gRPC服务器后,我可以通过在gRPC服务器上重新注册服务程序来在模拟模式和真实模式之间切换,例如:

服务器.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)

能够调用真实的硬件代码;或者通过交换对服务对象的引用,例如:

# 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客户端以模拟模式调用服务器时,我希望它应该回复(根据示例):"simulation">

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服务器并重新注册当然可以,但这不是我们想要的。)

我的一位好心同事给了我一个好建议:可以使用依赖注入概念。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

最新更新