docs icon indicating copy to clipboard operation
docs copied to clipboard

Cloud Functions python37: Future attached to a different loop

Open bryzgaloff opened this issue 5 years ago • 1 comments

I decided to create the issue in the docs repo. However, I don't know whether it is a right place to state the issue. Please point me to a correct place if it is needed.

Good news: python37 runtime environment allows to define handler as async def. This is a huge advantage versus sync-only handlers of AWS, for example.

Bad news: however, the handler is called using asyncio.run. This could be investigated from the traceback in case of exception: File \"/function/runtime/runtime.py\", line 157, in handle_event\n result = asyncio.run(result). This causes RuntimeError of Task … got Future … attached to a different loop if any of the resources are created outside the function (which is a common case for initialising a database connection) since asyncio.run creates a new loop.

Example code:

import aioch

ch = aioch.Client(…)  # attached to an initially created loop

async def echo(event, ctx):
    await ch.execute('SELECT 1')  # RuntimeError

Response:

{
    "errorMessage": "Task <Task pending coro=<echo() running at /function/code/index.py:16> cb=[_run_until_complete_cb() at /function/runtime/lib/python3.7/asyncio/base_events.py:157]> got Future <Future pending cb=[_chain_future.<locals>._call_check_cancel() at /function/runtime/lib/python3.7/asyncio/futures.py:351]> attached to a different loop",
    "errorType": "RuntimeError",
    "stackTrace": [
        "  File \"/function/runtime/runtime.py\", line 157, in handle_event\n    result = asyncio.run(result)\n",
        "  File \"/function/runtime/lib/python3.7/asyncio/runners.py\", line 43, in run\n    return loop.run_until_complete(main)\n",
        "  File \"/function/runtime/lib/python3.7/asyncio/base_events.py\", line 583, in run_until_complete\n    return future.result()\n",
        "  File \"/function/code/index.py\", line 16, in echo\n    await ch.execute('SELECT 1')\n",
        "  File \"/function/code/aioch/client.py\", line 38, in execute\n    **kwargs)\n"
    ]
}

The proper way to call async serverless functions handlers is asyncio.get_event_loop().run_until_complete(result) which preserves the initially created event loop. Please see a more detailed explanation in my Stack Overflow answer for Amazon Web Services.

Could you please provide any expectations on whether it will be fixed and when? Thank you in advance.

bryzgaloff avatar May 28 '20 10:05 bryzgaloff

Здравствуйте!

Вы можете попробовать протестировать новое поведение, использовав environment-переменную PYTHON_ASYNCIO_SAFE и присвоив ей значение True.

myusosnovskay avatar Nov 11 '21 13:11 myusosnovskay