我正在创建带有同步长期 GET 请求的 grpc python 客户端:
def main():
with grpc.insecure_channel(target='localhost:50051') as channel:
stub = hello_pb2_grpc.HelloStub(channel)
def signal_handler(signal, frame):
print("")
logging.warning("Interrupt signal. Exiting!")
channel.close()
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
...
while True:
logging.info("Sending request for control")
try:
resp = stub.GetControl(hello_pb2.GetControlRequest(
node=node_id
))
print("Got response: {}".format(resp))
...
如果用户使用Ctrl-C关闭python客户端并再次启动客户端,它将重新连接到具有不同端口的grpc服务器。
问题是:客户端应如何通知 grpc 服务器其退出,以便服务器应“丢弃”先前的连接?
几次客户端重新连接后,从服务器日志中我可以看到服务器尝试向不存在的对等方发送响应,没有任何错误:
INFO[0153] finished unary call with code OK grpc.code=OK grpc.method=GetControl grpc.service=world.World grpc.start_time="2021-02-19T12:41:17+01:00" grpc.time_ms=75479.79 peer.address="127.0.0.1:59976" span.kind=server system=grpc
INFO[0159] finished unary call with code OK grpc.code=OK grpc.method=GetControl grpc.service=world.World grpc.start_time="2021-02-19T12:41:05+01:00" grpc.time_ms=94089.74 peer.address="127.0.0.1:59862" span.kind=server system=grpc
注意:对等地址/端口不同。
使用客户端异步方法stub.GetControl会立即返回
future
,可以随时取消future.cancel()
取消API仅在异步方法中可用。同步 API 的目的是在返回之前完成所有工作,因此无法取消。顺便说一句,如果你想通知服务器,为什么不显式发送 RPC?您使用的
GetControl
方法是一元调用,不需要很长时间即可完成。如果您想要客户端/服务器之间更具交互性的通信,请尝试流式 RPC API。
我不知道它对你是否有用,但是当取消 RPC 时,gRPC 不会终止服务线程。因此,RPC请求将继续在服务器端处理。但是,您可以通过将
context.add_callback()
与 threading.Event()
方法结合使用来设置侦听器来检测完成/取消的 RPC 调用。设置事件后,您可以返回或引发异常。
stop_event = threading.Event()
def on_rpc_done():
stop_event.set()
context.add_callback(on_rpc_done)
does_some_process(stop_event)
def does_some_process(stop_event):
for i in range(0,10):
if stop_event.is_set():
return # Or raise