【问题标题】:Asyncio (Quart) throwing Task attached to a different loop error when connecting to MongoDB with motor使用电机连接到 MongoDB 时,Asyncio (Quart) 抛出附加到不同循环错误的任务
【发布时间】:2019-04-24 23:44:05
【问题描述】:

我使用 MongoDB 和 Motor.Asyncio 创建了一个带有 Quart 的 web 应用程序。 当应用程序尝试查询数据库时,会引发错误:

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: Task attached to a different loop 我补充说:

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

这并没有解决它。

这是第一次调用 motor 的块,错误发生的地方:

    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 上工作,应该不需要为电机创建特殊的循环。它在以前的版本中没有它的工作。所以我完全不知所措。

【问题讨论】:

    标签: mongodb python-3.7 quart motor-asyncio


    【解决方案1】:

    我找到了解决方案,基于这个问题: asyncio.run fails when loop.run_until_complete works

    那里提供的答案建议将 mongoDB 的初始化移动到 main() 内部。在这种特定情况下,因为这是一个 Quart 应用程序,所以没有 main 本身。但直觉仍然存在。

    我在模块级别定义了一个初始化函数,然后在调用 db 之前检查它是否已经初始化,如果没有,我调用初始化函数。

        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()
    

    这解决了我的问题。为什么我的代码在升级之前可以工作?我不知道。

    【讨论】:

      【解决方案2】:

      我知道它的回复晚了,但如果它也对其他人有帮助的话;

      您可以使用 Quart-Motor (pip install quart-motor) 并在应用程序的任何位置使用它。

      https://github.com/marirs/quart-motor/

      from quart_motor import Motor
      
      app = Quart(__name__)
      mongo = Motor(app,  uri='...')
      
      @app.route('/<user_name:str>')
      async def user_info(user_name):
          user = await mongo.db.users.find_one_or_404({"username": user_name})
          return render_template("user.html", user=user)
      

      注意:我是 Quart-Motor 的开发者

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 2019-05-11
        • 1970-01-01
        • 2018-09-28
        • 2019-12-17
        • 2018-08-06
        相关资源
        最近更新 更多