piccolo icon indicating copy to clipboard operation
piccolo copied to clipboard

InterfaceError- cannot perform operation: another operation is in progress

Open guruvignesh01 opened this issue 3 years ago • 1 comments

I get InterfaceError when execute get_or_create()

Models.objects().get_or_create(
        where=(........),
        defaults={
            ...............
        },
    ).run_sync(in_pool=False)

Logs:

Traceback (most recent call last):
  File "/home/-services/__pypackages__/3.10/lib/piccolo/engine/postgres.py", line 403, in _run_in_pool
    response = await connection.fetch(query, *args)
  File "/home/-services/__pypackages__/3.10/lib/asyncpg/connection.py", line 620, in fetch
    return await self._execute(
  File "/home/-services/__pypackages__/3.10/lib/asyncpg/connection.py", line 1658, in _execute
    result, _ = await self.__execute(
  File "/home/-services/__pypackages__/3.10/lib/asyncpg/connection.py", line 1683, in __execute
    return await self._do_execute(
  File "/home/-services/__pypackages__/3.10/lib/asyncpg/connection.py", line 1710, in _do_execute
    stmt = await self._get_statement(
  File "/home/-services/__pypackages__/3.10/lib/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-33' coro=<GetOrCreate.run() running at /home/-services/__pypackages__/3.10/lib/piccolo/query/methods/objects.py:58> cb=[_run_until_complete_cb() at /usr/local/lib/python3.10/asyncio/base_events.py:184]> got Future <Future pending cb=[Protocol._on_waiter_completed()]> attached to a different loop

During handling of the above exception, another exception occurred:
.
.
.
  instance = await self.query.get(self.where).run(
  File "/home/-services/__pypackages__/3.10/lib/piccolo/query/proxy.py", line 28, in run
    return await self.query.run(node=node, in_pool=in_pool)
  File "/home/-services/__pypackages__/3.10/lib/piccolo/query/methods/objects.py", line 121, in run
    objects = await self.query.run(
  File "/home/-services/__pypackages__/3.10/lib/piccolo/query/methods/objects.py", line 350, in run
    results = await super().run(node=node, in_pool=in_pool)
  File "/home/-services/__pypackages__/3.10/lib/piccolo/query/base.py", line 197, in run
    return await self._run(node=node, in_pool=in_pool)
  File "/home/-services/__pypackages__/3.10/lib/piccolo/query/base.py", line 179, in _run
    results = await engine.run_querystring(
  File "/home/-services/__pypackages__/3.10/lib/piccolo/engine/postgres.py", line 440, in run_querystring
    return await self._run_in_pool(query, query_args)
  File "/home/-services/__pypackages__/3.10/lib/piccolo/engine/postgres.py", line 402, in _run_in_pool
    async with self.pool.acquire() as connection:
  File "/home/-services/__pypackages__/3.10/lib/asyncpg/pool.py", line 220, in release
    raise ex
  File "/home/-services/__pypackages__/3.10/lib/asyncpg/pool.py", line 210, in release
    await self._con.reset(timeout=budget)
  File "/home/-services/__pypackages__/3.10/lib/asyncpg/connection.py", line 1366, in reset
    await self.execute(reset_query, timeout=timeout)
  File "/home/-services/__pypackages__/3.10/lib/asyncpg/connection.py", line 317, in execute
    return await self._protocol.query(query, timeout)
  File "asyncpg/protocol/protocol.pyx", line 323, in query
  File "asyncpg/protocol/protocol.pyx", line 707, in asyncpg.protocol.protocol.BaseProtocol._check_state
asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress
  

I execute some queries in run_sync() before executing get_or_create in run_sync command in the same flow.

When I pass get_or_create.....run_sync(in_pool=False) in the same flow, it works. What is the proper way to fix the issue?

guruvignesh01 avatar Jan 12 '23 16:01 guruvignesh01

So you've got something like this?

def my_function():
    some_query.run_sync()
    some_query.run_sync()
    MyTable.objects().get_or_create(MyTable.my_column == "foo").run_sync()

You might be better off just making the function async:

async def my_function():
    await some_query
    await some_query
    await MyTable.objects().get_or_create(MyTable.my_column == "foo")

>>> from piccolo.utils.sync import run_sync
>>> run_sync(my_function())

The error was probably happening because the sync code is using a shared connection pool, which can use some weirdness.

dantownsend avatar Jan 12 '23 17:01 dantownsend