aiocron
aiocron copied to clipboard
Aiocron broken w/ async-timeout == 4.0.1
With this code:
import logging
import threading
from . import schema
from aiohttp import web
import aiohttp_cors
from aiohttp_graphql import GraphQLView
from aiocron import crontab
logger = logging.getLogger(__name__)
host='0.0.0.0'
port='8011'
@crontab('*/1 * * * *')
async def callit():
logger.info('does this work?')
async def root(request):
with open('/app/ui/index.html') as f:
return web.Response(text=f.read(), content_type='text/html')
def main():
''' entry point '''
logging.basicConfig()
logger.setLevel(logging.DEBUG)
schema.logger.setLevel(logging.DEBUG)
logger.info('starting up...')
app = web.Application()
view = GraphQLView(schema = schema.schema)
cors = aiohttp_cors.setup(app)
route = cors.add(app.router.add_resource('/api/')).add_route('POST', view)
cors.add(route, {
'*': aiohttp_cors.ResourceOptions(
expose_headers='*',
allow_headers='*'
)
})
app.router.add_route('*', '/', root)
#app.router.add_static('/', path='/app/ui/')
web.run_app(app, host=host, port=port)
if __name__ == '__main__':
main()
This Works
and using async-timeout == 3.0.1, I get this output (using poetry):
INFO:__main__:starting up...
======== Running on http://0.0.0.0:8011 ========
(Press CTRL+C to quit)
INFO:__main__:does this work?
Here's the working poetry deps:
[tool.poetry.dependencies]
python = "^3.9"
graphene = "^2.1.8"
PyMySQL = "^1.0.2"
aiohttp_cors = "^0.7.0"
aiohttp-graphql = "^1.1.0"
aiocron = "^1.7"
O365 = "^2.0.15"
async-timeout = "3.0.1"
The Issue
when I switch to the latest (4.0.1), the callit() method never gets called. Here's the poetry deps:
[tool.poetry.dependencies]
python = "^3.9"
graphene = "^2.1.8"
PyMySQL = "^1.0.2"
aiohttp_cors = "^0.7.0"
aiohttp-graphql = "^1.1.0"
aiocron = "^1.7"
O365 = "^2.0.15"
async-timeout = "4.0.1"
... and the output is missing the log I expect.
INFO:__main__:starting up...
======== Running on http://0.0.0.0:8011 ========
(Press CTRL+C to quit)
This sure looks like library breakage. Thoughts?
Are you sure this is caused by asyncio-timeout? I've experimented some issues with aiohttp because it create a new loop in recent version. So if your web app use a loop which is not the one initiatialized while setting the cron, it won't work.
As I remember you can pass a loop to web.run_app. Give it a try.
Another solution is to initialize your cron when the webapp start. There's some hook for that.
If none of those works then you found a bug
No, I'm not sure of anything at the moment. Libraries updated on me and after debugging why I couldn't get any cron methods to fire, I found I can lightswitch the issue by rolling between 3.0.1 and 4.0.1 with async-timeout.
Thanks for the ideas. I'll give the loop tests a try. AFAIK, I'm not switching any loops around. If aiohttp or something else is, then I would think it would at least need to be documented.
Check those: https://github.com/aio-libs/aiohttp/pull/5572 / https://github.com/aio-libs/aiohttp/blob/master/aiohttp/web.py#L482
That was exactly the issue. aiohttp had changed from using asyncio.get_event_loop()
to asyncio.new_event_loop()
when no loop was passed in. There's several ways to get this to work, but I opted for passing the asyncio.get_event_loop()
into run_app(...)
like how it used to work just like @gawel suggested.
Thanks. Closing.