pythongrpcgrpc-python

gRPC server pytest error: statusCode.UNKNOWN


I implemented a small server and try with pytest to validate it:

@pytest.mark.asyncio
async def test_poc_server():
    # Start poc server
    server = PoCGrpcServer(50051)
    await server.start()
    # Create a client that connects to the server
    async with grpc.aio.insecure_channel('localhost:50051') as channel:
        stub = PoCStub(channel)
        response = await stub.Move(poc__pb2.MoveRequest(x=10.0, y=10.0))
    assert response.result() == poc__pb2.MoveResponse

And the test fails on the stub.Move() with the following error:


>           response = await stub.Move(poc__pb2.MoveRequest(x=10.0, y=10.0))

tests/test_grpc_server.py:51: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_AioCall of RPC that terminated with:
        status = Exception calling application: 
        details = "StatusCode.UNKNOWN"
        debu...peer  {created_time:"2023-06-15T14:38:59.0601+02:00", grpc_status:2, grpc_message:"Exception calling application: "}"
>

    def __await__(self) -> ResponseType:
        """Wait till the ongoing RPC request finishes."""
        try:
            response = yield from self._call_response
        except asyncio.CancelledError:
            # Even if we caught all other CancelledError, there is still
            # this corner case. If the application cancels immediately after
            # the Call object is created, we will observe this
            # `CancelledError`.
            if not self.cancelled():
                self.cancel()
            raise
    
        # NOTE(lidiz) If we raise RpcError in the task, and users doesn't
        # 'await' on it. AsyncIO will log 'Task exception was never retrieved'.
        # Instead, if we move the exception raising here, the spam stops.
        # Unfortunately, there can only be one 'yield from' in '__await__'. So,
        # we need to access the private instance variable.
        if response is cygrpc.EOF:
            if self._cython_call.is_locally_cancelled():
                raise asyncio.CancelledError()
            else:
>               raise _create_rpc_error(self._cython_call._initial_metadata,
                                        self._cython_call._status)
E               grpc.aio._call.AioRpcError: <AioRpcError of RPC that terminated with:
E                       status = StatusCode.UNKNOWN
E                       details = "Exception calling application: "
E                       debug_error_string = "UNKNOWN:Error received from peer  {created_time:"2023-06-15T14:38:59.0601+02:00", grpc_status:2, grpc_message:"Exception calling application: "}"
E               >

../../../../Library/Caches/pypoetry/virtualenvs/pytaf-6R8xcXyw-py3.11/lib/python3.11/site-packages/grpc/aio/_call.py:290: AioRpcError

I think it may have something to do with the server and client running both on the same asyncio runner but I'm not sure... What is interesting is that https://pypi.org/project/pytest-grpc/ shows the same error but it is not clear for me what the fix would be.


Solution

  • After many hours debugging, it seems like server.stop() was missing at the end of the call.

    It is pretty miss-leading as an error information but calling netstat -vanp tcp | grep 50051 enabled me to see that the port was kind of jammed and I had to kill one by one all the applications. By using ps aux | grep <pid> I could identify that previous running server where still there.

    After killing all of them and running the test once more, it went through (besides the assert that is failing)

    Conclusion

    "StatusCode.UNKNOWN" may mean that the port is blocked!