Search code examples
python-3.xpython-asynciopython-3.12

why does my python asyncio task report that it is done when it hasn't even been executed?


why does the task aioStartServerTask report that it is finished when it hasn't even been executed? If the task was executed there should be the output in the log file (which there isn't) and app.aioServer should be initialized and there wouldn't be the exception.

Python 3.12

from os import path as ospath
import asyncio
import socket as Socket
import logger as log

logger = log.getLogger(fileName=ospath.join('log', 'server.log'), initialize=True)

class App():
    def __init__(self) -> None:
        self.quit = False
        self.aioServer = None
        self.clients = []

    async def clientHandler(self, reader, writer):
        logger.info('client handler starting')

    async def aioServerStart(self):
        logger.info('aioServerStart')
        async def startServer(x=self):
            logger.info('here')
            ipaddr = Socket.gethostbyname(Socket.gethostname())
            port = 32843
            logger.info(f'starting socket server ({ipaddr}:{port})')
            x.aioServer = await asyncio.start_server(self.clientHandler, ipaddr, port=32843)
        return startServer

async def main():
    logger.info("server app starting")
    app = App()
    
    aioStartServerTask = asyncio.create_task(app.aioServerStart())
    logger.info(f'task done: {aioStartServerTask.done()}')
    logger.info('waiting for server to start...')
    await aioStartServerTask
    while not aioStartServerTask.done():
        await asyncio.sleep(.5)
        logger.info('waiting...')
    logger.info(f'task done: {aioStartServerTask.done()}')
    await asyncio.sleep(2)
    await aioStartServerTask
    logger.info('closing server')
    app.aioServer.close()
    await app.aioServer.wait_closed()
    logger.info('server closed')

if __name__ == '__main__':
    asyncio.run(main())

The output:

$ python server.py 
    INFO - 2024-09-29 19:42:49,861 - root - initialized logger - None
    INFO - 2024-09-29 19:42:49,861 - root - server app starting
    INFO - 2024-09-29 19:42:49,861 - root - task done: False
    INFO - 2024-09-29 19:42:49,862 - root - waiting for server to start...
    INFO - 2024-09-29 19:42:49,862 - root - aioServerStart
    INFO - 2024-09-29 19:42:49,862 - root - task done: True
    INFO - 2024-09-29 19:42:51,864 - root - closing server
Traceback (most recent call last):
  File "/home/david/python/opcua/server.py", line 79, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.12/asyncio/runners.py", line 194, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/base_events.py", line 687, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/home/david/python/opcua/server.py", line 74, in main
    app.aioServer.close()
    ^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'close'

Solution

  • I think you meant:

    def aioServerStart(self):
      ...
      return startServer()
    

    Otherwise the outer function doesn't do what you expect (instead of returning and making a task out of the internal, you make a task for the external). A simple typo I presume.

    Using return await startServer() is also an option depending on what exactly are you trying to achieve.