Search code examples
pythonpython-asyncioapscheduler

Starting an endless loop from an async function


I'm trying to periodically query an API. My code structure is as follows:

async def QueryData(): 
    print(datetime.datetime.now())

async def main():
    await TestApiConnection()
    
    scheduler = AsyncIOScheduler(timezone="Europe/Berlin")
    scheduler.add_job(QueryData, 'cron', minute='0-59')
    scheduler.start()
    try:
        asyncio.get_event_loop().run_forever()
    except (KeyboardInterrupt, SystemExit):
        pass
        scheduler.shutdown(wait=False)


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

The following error is thrown if I run this:

in run_forever assert self._self_reading_future is None AssertionError

If I turn the main function into a synchronous function, the QueryData job starts, by the result of TestApiConnection is not awaited anymore.

async def QueryData(): 
    print(datetime.datetime.now())

def main():
    TestApiConnection()
    ...

if __name__ == "__main__":
    main()

So how do I start the job from the async main method? Or should I restructure the code?


Solution

  • You cannot call run_forever() from the inside of an event loop, that function is intended for sync code that needs to fire up an event loop. When you use asyncio.run() you can simply await something that will never end. For example, you can replace asyncio.get_event_loop().run_forever() with:

    await asyncio.Event().wait()
    

    Also note that you don't need the pass before the call to scheduler.shutdown(). The sole purpose of the pass keyword is as an inert stand-in for places where the grammar requires a statement, and you have nothing to provide.