Search code examples
pythonapscheduler

APScheduler to call an async function


I've been having a heck of a time trying to schedule an async function. My understanding is that the AsyncIOScheduler will let me do just that, but in this particular code block, I'm not getting any joy.

Simply running a basic example works no problem:

from datetime import datetime 
import asyncio
from apscheduler.schedulers.asyncio import AsyncIOScheduler

async def tick():
    print(f"Tick! The async time is {datetime.now()}")

if __name__ == '__main__':
    scheduler = AsyncIOScheduler()
    scheduler.add_job(tick, 'interval', seconds=3)
    scheduler.start()

    try:
        asyncio.get_event_loop().run_forever()
    except (KeyboardInterrupt, SystemExit):
        pass

Produces:

Tick! The async time is 2021-07-01 18:47:43.503460
Tick! The async time is 2021-07-01 18:47:46.500421
Tick! The async time is 2021-07-01 18:47:49.500208
^C%                                               

However my code block is erroring out with various things about callables, and proceeding to tell me that seed was never awaited. It awaits just fine called from main() right before setting up the scheduler, but maybe that's a red herring?

I'm no python expert, so please be somewhat gentle :)

Thanks in advance for any clue.

import asyncio
from apscheduler.schedulers.asyncio import AsyncIOScheduler
import c_seed
import c_logging


client = 'async'
state = 'live'
account = 'spot'

async def main():
    c_logging.logging.info("")
    c,l = await c_seed.init(client,state,account)
    await c_seed.seed(c,l)
    scheduler = AsyncIOScheduler()
    scheduler.add_job(c_seed.seed(c,l), 'interval', seconds=60)
    scheduler.start()

if __name__ == "__main__":
    c_logging.logging.info("")
    asyncio.run(main())
2021-07-01 18:43:59,943 [INFO] <module>: c_client
2021-07-01 18:43:59,944 [INFO] <module>: 
2021-07-01 18:43:59,945 [DEBUG] __init__: Using selector: KqueueSelector
2021-07-01 18:43:59,945 [INFO] main: 
2021-07-01 18:43:59,945 [INFO] init: 
2021-07-01 18:43:59,945 [INFO] create: c_client
2021-07-01 18:43:59,945 [INFO] create: c_client -> async
2021-07-01 18:43:59,945 [INFO] create: c_client -> live
2021-07-01 18:44:00,591 [INFO] pairs_list: 
2021-07-01 18:44:00,753 [DEBUG] seed: async seed start
2021-07-01 18:44:07,040 [DEBUG] seed: async seed complete
Traceback (most recent call last):
  File "/Users/Documents/Development/main.py", line 58, in <module>
    asyncio.run(main()) 
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/Users/Documents/Development/main.py", line 36, in main
    scheduler.add_job(c_seed.seed(c,l), 'interval', seconds=60)
  File "/Users/Documents/Development/.venv/lib/python3.8/site-packages/apscheduler/schedulers/base.py", line 439, in add_job
    job = Job(self, **job_kwargs)
  File "/Users/Documents/Development/.venv/lib/python3.8/site-packages/apscheduler/job.py", line 49, in __init__
    self._modify(id=id or uuid4().hex, **kwargs)
  File "/Users/Documents/Development/.venv/lib/python3.8/site-packages/apscheduler/job.py", line 170, in _modify
    raise TypeError('func must be a callable or a textual reference to one')
TypeError: func must be a callable or a textual reference to one
sys:1: RuntimeWarning: coroutine 'seed' was never awaited

Solution

  • The comment from Paul Cornelius is correct. You have to schedule coroutine functions like any other functions:

    scheduler.add_job(c_seed.seed, 'interval', seconds=60, args=(c,l))