python gRPC client disconnect while server streaming response

Question:

Good day,

This is my first time posting so forgive me if I do something wrong with the post.
I am trying to get a subscription type service running, which works fine up until the client disconnects. Depending on the timing, this works fine or blocks indefinitely.

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

I am new to gRPC so there’s possibly a few things I’m doing wrong, but my main issue is that if the client disconnects just before/while the yield occurs, the code hangs indefinitely. I’ve tried a few things to get out of this situation but they only work some times. A timeout set on the client side does count down, but the yield doesn’t end when the countdown hits 0. The callback happens fine, but context.cancel and context.abort do not seem to help here either.

Is there anything I can do to prevent the yield from hanging or set a timeout of some sort so the the yield eventually ends? Any help/advice is greatly appreciated.

Asked By: Vernon Naidoo

||

Answers:

If anyone else comes across this issue, there isn’t really a problem here. I erroneously thought that this was blocking since none of the code I put in to print progression was printing.

In actuality, when the client disconnects and the server tries to yield an exception is thrown… it just isn’t a General “Exception”, or “SystemExit”, or “SystemError”. Not exactly sure what the exception type is for for this, but the code does exit properly if you do whatever cleanup you need in a “finally”.

Answered By: Vernon Naidoo

You can catch it using GeneratorExit exception

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

When client disconnected in middle of gRPC function process, it will raise GeneratorExit exception in server-side. It cannot catch by default Exception.

Answered By: jon_17z
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.