RuntimeError using asynpcg and fastapi running async function: Task attached to a different loop

See original GitHub issue

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn’t find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google “How to X in FastAPI” and didn’t find any information.
  • I already read and followed all the tutorial in the docs and didn’t find an answer.
  • I already checked if it is not related to FastAPI but to Pydantic.
  • I already checked if it is not related to FastAPI but to Swagger UI.
  • I already checked if it is not related to FastAPI but to ReDoc.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

# api.py
from fastapi import FastAPI

class API:
    def __init__(self, client):
        self.app = FastAPI()
        self.client = client

    async def get_user_locker(self, user_id: int):
        locker = await self.client.database.get_user_locker(user_id)
        characters = self.client.characters.get_by_id(locker)
        return characters

# main.py
from telegram import TelegramClient
from api import API

from threading import Thread

import asyncio
import uvicorn
import sys

async def start():

    client = TelegramClient("test")
    await client.start()

    api = API(client)
    api.app.add_api_route("/locker/{user_id}", api.get_user_locker)

    Thread(target=lambda: uvicorn.run(
            api.app, host="0.0.0.0", port=5002
    ), daemon=True).start()
 
    await client.database.init()
    print("Client started as @{}".format(client.me.username))   
    while True:
        await asyncio.sleep(600)

if __name__ == "__main__":
    try:
        asyncio.run(start())
    except KeyboardInterrupt:
        print("Shutting down...")
        sys.exit(0)

# telegram.py
from characters import Characters
from database import Database

import pyrogram
import json

class TelegramClient(pyrogram.Client):
    def __init__(self, name):
        super().__init__(
            name="sessions/" + name,
            api_id="123",
            api_hash="abc",
            plugins=dict(root="handlers")
        )
        self.banned_list = []
        self.translations = json.load(open("translations.json"))
        self.database = Database(database="waifu")
        self.characters = Characters("char.json", lambda x: x.likes >= 50)

    def get_translation(self, name, language):
        try:
            return self.translations[name][language]
        except:
            return "TRANSLATION_NOT_FOUND"

    async def spawn(self, group: dict):
        chat_id = group["chat_id"]
        character = await self.characters.get_random()
        await self.database.set_current(chat_id, character.id)
        return await self.send_photo(chat_id, character.image,
            caption=self.get_translation("character_spawned", group["language"]), 
        )

Description

I run the script. Everything works fine. But, when i reach the endpoint /locker/user_id, I get an Internal Error. Checking the shell i see a huge traceback. The database i use is PosgteSQL with asyncpg module. The error raises when an async function is ran in the FastAPI handler. I can run the same function totally fine outside of FastAPI:

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/home/wicked/.local/lib/python3.9/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/home/wicked/.local/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/home/wicked/.local/lib/python3.9/site-packages/fastapi/applications.py", line 270, in __call__
    await super().__call__(scope, receive, send)
  File "/home/wicked/.local/lib/python3.9/site-packages/starlette/applications.py", line 124, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/wicked/.local/lib/python3.9/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/home/wicked/.local/lib/python3.9/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/home/wicked/.local/lib/python3.9/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/home/wicked/.local/lib/python3.9/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/home/wicked/.local/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/home/wicked/.local/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/home/wicked/.local/lib/python3.9/site-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/home/wicked/.local/lib/python3.9/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/home/wicked/.local/lib/python3.9/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "/home/wicked/.local/lib/python3.9/site-packages/fastapi/routing.py", line 235, in app
    raw_response = await run_endpoint_function(
  File "/home/wicked/.local/lib/python3.9/site-packages/fastapi/routing.py", line 161, in run_endpoint_function
    return await dependant.call(**values)
  File "/home/wicked/bots/waifu/api.py", line 9, in get_user_locker
    locker = await self.client.database.get_user_locker(user_id)
  File "/home/wicked/bots/waifu/database.py", line 31, in get_user_locker
    query = await self.conn.fetchrow("SELECT locker FROM users WHERE user_id = $1;", user_id)
  File "/home/wicked/.local/lib/python3.9/site-packages/asyncpg/connection.py", line 678, in fetchrow
    data = await self._execute(
  File "/home/wicked/.local/lib/python3.9/site-packages/asyncpg/connection.py", line 1658, in _execute
    result, _ = await self.__execute(
  File "/home/wicked/.local/lib/python3.9/site-packages/asyncpg/connection.py", line 1683, in __execute
    return await self._do_execute(
  File "/home/wicked/.local/lib/python3.9/site-packages/asyncpg/connection.py", line 1710, in _do_execute
    stmt = await self._get_statement(
  File "/home/wicked/.local/lib/python3.9/site-packages/asyncpg/connection.py", line 397, in _get_statement
    statement = await self._protocol.prepare(
  File "asyncpg/protocol/protocol.pyx", line 168, in prepare
RuntimeError: Task <Task pending name='Task-52' coro=<RequestResponseCycle.run_asgi() running at /home/wicked/.local/lib/python3.9/site-packages/uvicorn/protocols/http/httptools_impl.py:419> cb=[set.discard()]> got Future <Future pending cb=[Protocol._on_waiter_completed()]> attached to a different loop

Operating System

Linux

Operating System Details

Debian 11

FastAPI Version

0.88.0

Python Version

Python 3.9.2

Additional Context

No response

Issue Analytics

  • State:closed
  • Created 9 months ago
  • Comments:8

github_iconTop GitHub Comments

3reactions
stefanodvxcommented, Dec 15, 2022

This worked. Now everything works fine. Thank you so much 😄

0reactions
jgould22commented, Dec 15, 2022

Sorry I was not clear, I mean like they describe here in the uvicorn docs https://www.uvicorn.org/#config-and-server-instances

Specifically where it says If you'd like to run Uvicorn from an already running async environment

Read more comments on GitHub >

github_iconTop Results From Across the Web

getting task attached to a different loop runtime error when ...
i am trying to create an app with mongodb client motor and fastapi . I created seperate routes and a seperate file to...
Read more >
Future task attached to a different loop - python - Stack Overflow
You can have mongodb motor client in the global scope, but creating and closing it should be done inside an async function.
Read more >
Async Tests - FastAPI
If you encounter a RuntimeError: Task attached to a different loop when integrating asynchronous function calls in your tests (e.g. when using MongoDB's ......
Read more >
Common Mistakes Using Python3 asyncio
4. Task/Future is awaited in a different EventLoop than it is created ... Compared to C# async/await , the interfaces of Python3 asyncio...
Read more >
Asynchronous I/O (asyncio) - SQLAlchemy 1.4 Documentation
Using awaitable-only driver methods in connection pool and other events ... RuntimeError: Event loop is closed within garbage collection.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found