Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot perform operation: another operation is in progress #728

Open
erhosen opened this issue Oct 1, 2020 · 4 comments
Open

Cannot perform operation: another operation is in progress #728

erhosen opened this issue Oct 1, 2020 · 4 comments

Comments

@erhosen
Copy link

erhosen commented Oct 1, 2020

  • GINO version: 1.0.1
  • Python version: 3.8
  • asyncpg version: 0.21.0
  • aiocontextvars version: 0.2.2
  • PostgreSQL version: 10.14

Description

My task is create some database record (via GINO Model.create()) before running test (typical pytest.fixture usage), and drop everything after.

What I Did

conftest.py

import pytest
from fastapi.testclient import TestClient

from alembic.config import main as alembic_main

from settings import settings
settings.DATABASE_NAME = 'test_db_name'
from main import app_init

@pytest.fixture
def client():
    alembic_main(["--raiseerr", "upgrade", "head"])

    with TestClient(app_init()) as client:
        yield client

    alembic_main(["--raiseerr", "downgrade", "base"])

test.py

import pytest
from models import SpecialModel

@pytest.fixture
async def special_model():
    special_model = await SpecialModel.create(
        internal_name='internal_name',
        comment='comment',
        is_active=True,
        title="Title",
        text="Text"
    )
    yield special_model

def test_get_all_special_models(client, special_model):
    response = client.get("api/get_all_models")
    data = response.json()
    assert data["success"] is True
    assert len(data["result"]) == 1

What I got:

test setup failed
@pytest.fixture
    async def special_model():
>      special_model = await SpecialModel.create(
            internal_name='internal_name',
            comment='comment',
            is_active=True,
            title="Title",
            text="Text"
        )

tests/test.py:8: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/crud.py:444: in _create_without_instance
    return await cls(**values)._create(bind=bind, timeout=timeout)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/crud.py:477: in _create
    row = await bind.first(q)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/engine.py:748: in first
    return await conn.first(clause, *multiparams, **params)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/engine.py:147: in __aexit__
    await conn.release()
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/engine.py:279: in release
    await dbapi_conn.release(True)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/engine.py:47: in release
    return await self._release()
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/engine.py:83: in _release
    await self._pool.release(conn)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/dialects/asyncpg.py:232: in release
    await self._pool.release(conn)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/asyncpg/pool.py:654: in release
    return await asyncio.shield(ch.release(timeout))
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/asyncpg/pool.py:216: in release
    raise ex
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/asyncpg/pool.py:206: in release
    await self._con.reset(timeout=budget)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/asyncpg/connection.py:1137: in reset
    await self.execute(reset_query, timeout=timeout)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/asyncpg/connection.py:295: in execute
    return await self._protocol.query(query, timeout)
asyncpg/protocol/protocol.pyx:301: in query
    ???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???
E   asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress
@uriyyo
Copy link
Contributor

uriyyo commented Nov 5, 2020

@erhosen I faced the same problem, solution was to use a separate db connection:

@pytest.fixture
async def special_model():
    async with db.acquire():  # use seperate db connection
        special_model = await SpecialModel.create(
            internal_name='internal_name',
            comment='comment',
            is_active=True,
            title="Title",
            text="Text"
        )

    yield special_model

This isn't an issue with gino it's an asyncpg issue. Basically, asyncpg can't make two concurrent queries using the same db connection.

@fantix
Copy link
Member

fantix commented Dec 7, 2020

Thanks! This deserves a page in the docs.

@kgantsov
Copy link

I have the same exception asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress when I run pytest.

Any idea what I did wrong? I would appreciate any help. Thanks in advance.

requirements.txt

fastapi==0.70.0
gino==1.0.1
pytest==6.2.5
pytest-asyncio==0.16.0
requests==2.26.0

test_code.py

import os
from typing import List
import pytest

from gino import Gino
from fastapi import APIRouter
from pydantic import BaseModel
from fastapi import FastAPI
from starlette.testclient import TestClient

router = APIRouter()

db = Gino()


async def init_db():
    await db.set_bind(os.environ['DATABASE_URL'])
    await db.gino.create_all()


class UserModel(db.Model):
    __tablename__ = 'user'

    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.Unicode())
    email = db.Column(db.Unicode(), unique=True, index=True)
    password_hash = db.Column(db.Unicode())


class UserSchema(BaseModel):
    id: int = 0
    name: str
    email: str
    password: str


class UserListSchema(BaseModel):
    objects: List[UserSchema]


@router.get("/users/", response_model=UserListSchema)
async def get_users():
    async with db.acquire():
        users = await UserModel.query.limit(200).gino.all()

    return UserListSchema.parse_obj({
        'objects': [x.to_dict() for x in users]
    })


def get_app():
    print('INIT APP')
    app = FastAPI(title="GINO FastAPI Demo")

    app.include_router(router, prefix='/API/v1')

    @app.on_event("startup")
    async def startup_event():
        print('Initialising DB')
        await init_db()
        print('DB was initialised')

    return app


@pytest.fixture
def client():

    with TestClient(get_app()) as client:
        yield client


@pytest.fixture
@pytest.mark.anyio
async def user(client):

    print('[-------->')
    # await init_db()

    # async with db.acquire():
    user = await UserModel.create(email='test@gmail.com')

    # async with db.acquire():
    users = await UserModel.query.limit(200).gino.all()
    print('.....=', user)
    print('....._', users)

    yield user


def test_users(user, client):
    response = client.get(
        "/API/v1/users",
        headers={},
    )
    print('=====', user, response.text)

    assert response.status_code == 200
    assert response.json() == {}

@MarkParker5
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants