Asyncio (Quart) throwing Task, связанный с другой ошибкой цикла при подключении к MongoDB с мотором - PullRequest
1 голос
/ 25 апреля 2019

Я создал веб-приложение с Quart, используя MongoDB и Motor.Asyncio.Когда приложение пытается запросить БД, выдается ошибка:

Task <Task pending coro=<ASGIHTTPConnection.handle_request() 
running at /home/user/.local/lib/python3.7/site-packages/quart
/asgi.py:59> cb=[_wait.<locals>._on_completion() at /usr/lib/python3.7
/asyncio/tasks.py:440]> got Future <Future pending cb=[run_on_executor.
<locals>._call_check_cancel() at /home/user/.local/lib/python3.7/site-
packages/motor/frameworks/asyncio/__init__.py:80]> attached to a 
different loop

Я не понимаю, почему это происходит, или не знаю, как ее решить.

Приложение было запущенобез проблем, но я решил обновить Python 3.6 (на Ubuntu-18.04) до python 3.7.1.С этим я обновил Quart до 0.9.0.В результате этого обновления произошла вышеуказанная ошибка.

Приложение запускается из командной строки с Hypercorn и Nginx.

Я не уверен, какие части моего кода актуальны в этом случае

Сначала импортирую Quart, затем Motor:

    # Mongodb / Gridfs with Motor
    import motor.motor_asyncio
    from pymongo import ReturnDocument
    from bson.objectid import ObjectId
    from bson.son import SON

    client = motor.motor_asyncio.AsyncIOMotorClient()
    db = client.myDataBase
    fs = motor.motor_asyncio.AsyncIOMotorGridFSBucket(db)

После этого добавляю:

    app = Quart(__name__)

Я пытался переместить это, прежде чем блок импорта мотора ничего не изменил.

Как предложено в вопросе / ответе: RuntimeError: Задача присоединена к другому циклу Я добавил:

    loop=asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    client = motor.motor_asyncio.AsyncIOMotorClient(io_loop=loop)

Это не решило ее.

Это блок, в котором был сделан первый вызов двигателя и где произошла ошибка:

    try:
        session_info = await db.sessions.find_one(
            {
                'session_id': uuid.UUID(session_id)
            },
            {
                'username':True,
                '_id':False
            }
        )
    except Exception as e:
        print('error retrieving session info:', e)

Я могу проигнорировать ошибку и продолжить, но затем будет сделан следующий вызов и возникнет та же ошибка.

Я понимаю, что Quart работает со стандартным значением event_loop, и не нужно создавать специальный цикл для двигателя.Это работает без него в предыдущей версии.Так что я в полной растерянности.

1 Ответ

1 голос
/ 25 апреля 2019

Я нашел решение, основываясь на этом вопросе: asyncio.run не работает, когда loop.run_until_complete работает

Ответ, предложенный там, предлагает перенести инициализацию mongoDB внутрь main().В данном конкретном случае, поскольку это приложение Quart, основной части нет.Но интуиция остается.

Я определил функцию инициализации на уровне модуля, затем перед вызовом в базу данных проверяю, инициализирована ли она, если нет, то я вызываю функцию инициализации.

    import motor.motor_asyncio
    from pymongo import ReturnDocument
    from bson.objectid import ObjectId
    from bson.son import SON

    client = None
    db = None
    fs = None

    async def connect_to_mongo():
        global client, db, fs
        client = motor.motor_asyncio.AsyncIOMotorClient()
        db = client.myDataBase
        fs = motor.motor_asyncio.AsyncIOMotorGridFSBucket(db)

затем перед вызовом в базу данных:

    if db is None:
        await connect_to_mongo()

Это решило мою проблему.Почему мой код работал до обновления?Я не знаю.

...