Dinnerbone / mcstatus

A Python class for checking the status of an enabled Minecraft server

Home Page:http://dinnerbone.com/minecraft/tools/status/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Synchronous operations inside async functions

ba1dr opened this issue · comments

mcstatus==8.0.0

I have a hanging process while I query servers in async mode. This happens not always - 1-2 times a day.
I managed to reproduce this only after 3 hours in infinite loop of polling 100+ servers.
See stacktrace below.

...
  File "/opt/myfolder/some_file.py", line 145, in async_query
    return await mcserver.async_query(tries=2)
  File "/usr/local/lib/python3.9/dist-packages/mcstatus/server.py", line 193, in async_query
    await querier.handshake()
  File "/usr/local/lib/python3.9/dist-packages/mcstatus/querier.py", line 70, in handshake
    self.challenge = int(packet.read_ascii())
  File "/usr/local/lib/python3.9/dist-packages/mcstatus/protocol/connection.py", line 80, in read_ascii
    result.extend(self.read(1))
KeyboardInterrupt

As I can see there are lots of synchronous operations in functions defined as async.

...
class AsyncServerQuerier(ServerQuerier):
    async def _read_packet(self):
        packet = Connection()
...

    async def handshake(self):
        await self.connection.write(self._create_handshake_packet())

        packet = await self._read_packet()
        self.challenge = int(packet.read_ascii())

...

here read_ascii() is a sync operation.

Next: QueryResponse.from_connection() is sync too.

And so on..

Thanks for the report!

Following the code leads me to believe that the asynchronous AsyncReadConnection.read_ascii relies on an asynchronous UDPAsyncSocketConnection.read, but as you pointed out there is a spot in the AsyncServerQuerier that is creating a synchronous Connection that is used by some of the other functions. I'll mark it as a bug.