服务器流响应时 python gRPC 客户端断开连接

问题描述 投票:0回答:3

美好的一天,

这是我第一次发帖,如果我的帖子有什么不对的地方,请原谅我。 我正在尝试运行订阅类型的服务,该服务可以正常工作,直到客户端断开连接。根据时间的不同,这可以正常工作或无限期地阻塞。

def Subscribe(self, request, context):
    words = ["Please", "help", "me", "solve", "my", "problem", "!"] 

    while context.is_active():
        try:
            for word in words:
                event = fr_pb2.Event(word=word)
                if not context.is_active():
                    break
                yield event
                print (event)                    
        except Exception as ex:
            print(ex)
            context.cancel()

    print("Subscribe ended")

我是 gRPC 新手,所以我可能做错了一些事情,但我的主要问题是,如果客户端在屈服发生之前/同时断开连接,代码将无限期挂起。我尝试了一些方法来摆脱这种情况,但它们只在某些时候有效。客户端设置的超时确实会倒计时,但当倒计时达到 0 时,收益并不会结束。回调发生得很好,但 context.cancel 和 context.abort 似乎在这里也没有帮助。

我可以采取什么措施来防止收益挂起或设置某种超时以便收益最终结束?非常感谢任何帮助/建议。

python stream grpc yield
3个回答
1
投票

如果其他人遇到这个问题,那么这里并不是真正的问题。我错误地认为这是阻塞的,因为我输入的用于打印进度的代码都没有被打印。

实际上,当客户端断开连接并且服务器尝试抛出异常时......它不是一般的“异常”、“系统退出”或“系统错误”。不完全确定异常类型的用途是什么,但是如果您在“finally”中执行所需的任何清理,代码确实会正确退出。


1
投票

您可以使用 GeneratorExit 异常捕获它

def Subscribe(self, request, context):
   try:
       words = ["Please", "help", "me", "solve", "my", "problem", "!"] 

       while context.is_active():
            for word in words:
                 event = fr_pb2.Event(word=word)
                 if not context.is_active():
                     break
                 yield event
                 print (event)                    
   except GeneratorExit:
        print("Client disconnected before function finished!")
   finally:
        print("Subscribe ended")

当客户端在 gRPC 函数处理过程中断开连接时,会在服务器端引发 GeneratorExit 异常。它默认无法捕获异常。


0
投票

在 grpc python 1.58.0 中,没有 context.is_active() 方法。请参阅文档

要捕获客户端取消/断开连接,请尝试捕获 asyncio.CancelledError 错误。

def Subscribe(self, request, context):
    words = ["Please", "help", "me", "solve", "my", "problem", "!"] 

    while True:
        try:
            for word in words:
                event = fr_pb2.Event(word=word)
                yield event
                print (event)                    
        except asyncio.CancelledError as ex:
            print(ex)
            context.cancel()

    print("Subscribe ended")
© www.soinside.com 2019 - 2024. All rights reserved.