gawel / aiocron

Crontabs for asyncio
MIT License
343 stars 21 forks source link

Aiocron broken w/ async-timeout == 4.0.1 #21

Closed bartonology closed 2 years ago

bartonology commented 2 years ago

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?

gawel commented 2 years ago

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

bartonology commented 2 years ago

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.

gawel commented 2 years ago

Check those: https://github.com/aio-libs/aiohttp/pull/5572 / https://github.com/aio-libs/aiohttp/blob/master/aiohttp/web.py#L482

bartonology commented 2 years ago

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.