Search code examples
pythonasynchronouspython-asyncioapscheduler

How to use AsyncIOScheduler to run function from another function?


I'm having difficulty to understand how the AsyncIOScheduler works and how I can schedule a function inside the main function, or how is the proper way to do that.

How can I run the function foo every 10 seconds?

Suppose I have this structure:

package/
    controllers.py
    main.py

From the file controllers.py I've got a function called foo and the function is something like this:

async def foo():
    print('Hello World')

I'd like to run the function foo (and many others) from the file main.py, and this file is like:

import asyncio
from controllers import foo, bar
from apscheduler.schedulers.asyncio import AsyncIOScheduler

async def main():

    # Init message
    print('\nPress Ctrl-C to quit at anytime!\n' )
    
    await asyncio.create_task(bar())

    scheduler = AsyncIOScheduler()
    scheduler.add_job(await asyncio.create_task(foo()), "interval", seconds=10)
    scheduler.start()

if __name__ == "__main__":
    while True:
        try:
            asyncio.run(main())
        except Exception as e:
            print("Exception: " + str(e))

Is it right to run the scheduler this way? Or the timer will be reseted every time the main function is running?

I tried the code below, the loop interval works, but the main function not.

import asyncio
from controllers import foo, bar
from apscheduler.schedulers.asyncio import AsyncIOScheduler

async def main():

    # Init message
    print('\nPress Ctrl-C to quit at anytime!\n' )
    
    await asyncio.create_task(bar())

if __name__ == "__main__":

    scheduler = AsyncIOScheduler()
    scheduler.add_job(foo, "interval", seconds=10)
    scheduler.start()

    while True:
        try:
            asyncio.get_event_loop().run_forever()
            asyncio.run(main())
        except Exception as e:
            print("Exception: " + str(e))

If I changed the order from:

            asyncio.get_event_loop().run_forever()
            asyncio.run(main())

to:

            asyncio.run(main())
            asyncio.get_event_loop().run_forever()

I get the error: There is no current event loop in thread 'MainThread'.

The loop works (scheduler only), but the main function is not running, how can I put those together in loop?


Solution

  • I suppose you want to run you main() function forever, so you can try it in this way.

    controllers.py

    from datetime import datetime
    
    
    async def foo():
        print(f'{datetime.now()} Foo')
    
    
    async def bar():
        print(f'{datetime.now()} Bar')
    

    main.py

    import asyncio
    from controllers import foo, bar
    from apscheduler.schedulers.asyncio import AsyncIOScheduler
    
    
    async def main():
        # Init message
        print('\nPress Ctrl-C to quit at anytime!\n')
    
        scheduler = AsyncIOScheduler()
        scheduler.add_job(foo, "interval", seconds=2)
        scheduler.start()
        
        while True:
            await asyncio.create_task(bar())
            await asyncio.sleep(1)
    
    
    if __name__ == "__main__":
        loop = asyncio.get_event_loop()
        loop.create_task(main())
        loop.run_forever()
    

    Output:

    Press Ctrl-C to quit at anytime!
    2022-01-09 03:38:10.468914 Bar
    2022-01-09 03:38:11.472966 Bar
    2022-01-09 03:38:12.468882 Foo
    2022-01-09 03:38:12.473449 Bar
    2022-01-09 03:38:13.477678 Bar
    2022-01-09 03:38:14.469389 Foo
    2022-01-09 03:38:14.480098 Bar
    2022-01-09 03:38:15.483889 Bar
    2022-01-09 03:38:16.472584 Foo
    2022-01-09 03:38:16.487105 Bar
    2022-01-09 03:38:17.492550 Bar
    2022-01-09 03:38:18.467403 Foo
    2022-01-09 03:38:18.493330 Bar
    2022-01-09 03:38:19.496680 Bar
    2022-01-09 03:38:20.471553 Foo
    2022-01-09 03:38:20.499928 Bar
    2022-01-09 03:38:21.503572 Bar
    2022-01-09 03:38:22.470329 Foo
    2022-01-09 03:38:22.505597 Bar
    2022-01-09 03:38:23.510854 Bar
    2022-01-09 03:38:24.471455 Foo
    ...
    

    Also, you can run periodic functions without using AsyncIOScheduler like this.