Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StopAsyncIteration exception when adding python aio.UnaryStreamClientInterceptor no-op interceptor #36581

Closed
wconti27 opened this issue May 10, 2024 · 1 comment

Comments

@wconti27
Copy link

wconti27 commented May 10, 2024

I am trying to add an aio.UnaryStreamClientInterceptor to my grpc client, but am hitting StopAsyncIteration exceptions. I am following the example here for async python streaming. After adding a no-op interceptor, I am getting the exception.

What version of gRPC and what language are you using?

Python and grpcio==1.63.0

What operating system (Linux, Windows,...) and version?

MacOs

What runtime / compiler are you using (e.g. python version or version of gcc)

python 3.11

What did you do?

Please provide either 1) A unit test for reproducing the bug or 2) Specific steps for us to follow to reproduce the bug. If there’s not enough information to debug the problem, gRPC team may close the issue at their discretion. You’re welcome to re-open the issue once you have a reproduction.

What did you expect to see?

No StopAsyncIteration exception

What did you see instead?

error (code is below):

Greeter client received from direct read: Hello number 9, will!
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/Users/william.conti/Documents/repos/apm-fi-demo-apps/sample-apps/python/grpc/f342630b8815ccb08b8445e1864c0012/async_greeter_client_with_interceptor.py", line 58, in <module>
    asyncio.run(run())
  File "/Users/william.conti/.pyenv/versions/3.11.3/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/Users/william.conti/.pyenv/versions/3.11.3/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/william.conti/.pyenv/versions/3.11.3/lib/python3.11/asyncio/base_events.py", line 653, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/Users/william.conti/Documents/repos/apm-fi-demo-apps/sample-apps/python/grpc/f342630b8815ccb08b8445e1864c0012/async_greeter_client_with_interceptor.py", line 48, in run
    response = await hello_stream.read()
               ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/william.conti/Documents/repos/apm-fi-demo-apps/sample-apps/python/grpc/f342630b8815ccb08b8445e1864c0012/venv/lib/python3.11/site-packages/grpc/aio/_interceptor.py", line 502, in read
    return await self._response_aiter.asend(None)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
StopAsyncIteration

code:

import asyncio
import logging

import grpc
import hellostreamingworld_pb2
import hellostreamingworld_pb2_grpc


class StreamInterceptor(grpc.aio.UnaryStreamClientInterceptor):
    async def intercept_unary_stream(self, continuation, call_details, request):
        response_iterator = await continuation(call_details, request)
        return response_iterator


async def run() -> None:
    async with grpc.aio.insecure_channel("localhost:50051", interceptors=[StreamInterceptor()]) as channel:
        stub = hellostreamingworld_pb2_grpc.MultiGreeterStub(channel)

        # Read from an async generator
        async for response in stub.sayHello(
            hellostreamingworld_pb2.HelloRequest(name="you")
        ):
            print(
                "Greeter client received from async generator: "
                + response.message
            )

        # Direct read from the stub
        hello_stream = stub.sayHello(
            hellostreamingworld_pb2.HelloRequest(name="will")
        )
        while True:
            response = await hello_stream.read()
            if response == grpc.aio.EOF:
                break
            print(
                "Greeter client received from direct read: " + response.message
            )


if __name__ == "__main__":
    logging.basicConfig()
    asyncio.run(run())

See TROUBLESHOOTING.md for how to diagnose problems better.

Anything else we should know about your project / environment?

No, i am running the simple example from above.

@XuanWang-Amos
Copy link
Contributor

Thanks for raising this issue! Looks like we should return grpc.aio.EOF in this case as documented here:

async def read(self) -> Union[EOFType, ResponseType]:
"""Reads one message from the stream.
Read operations must be serialized when called from multiple
coroutines.
Note that the iterator and read/write APIs may not be mixed on
a single RPC.
Returns:
A response message, or an `grpc.aio.EOF` to indicate the end of the
stream.
"""

I'll create a PR to fix this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants